分布式锁 基于Redis

分布式锁的实现(基于Redis)

参考:http://www.jb51.net/article/75439.htm 

        http://www.linuxidc.com/Linux/2015-01/111827.htm 

        http://www.tuicool.com/articles/6juqmm7 

 方式一: 基于第三方类库 redssion 

1.安装redis

安装redssion的锁服务队redis的版本有要求,要求必须高于2.6版本。关于redis的安装,请参考redis安装

2.redssion库

redssion的库添加的pom文件中去。

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>2.1.0</version>
</dependency>

3.测试例子

 Config config = new Config();
        config.useSingleServer().setAddress("ipaddress:6379");
        Redisson redisson = Redisson.create(config);
        
        for(int i=0;i<5;i++){
        RLock lock = redisson.getLock("testLock");
        lock.lock(10, TimeUnit.SECONDS);//10s超时
        logger.info("the lock client id is client{}",i);
        Thread.sleep(1000);
        logger.info("client{} unlock",i);
        lock.unlock();
        }

4.参考

redisson

方式二: 自定义代码实现 



import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

/**
* redis实现的分布式锁
*/
public final class Lock {

private static final String LOCK = "redis:lock:%s";
private static final int EXPIRE = 20 * 60;//20分钟
private static final Logger logger = LoggerFactory.getLogger(Lock.class);

private Lock() {
}


public static Lock getLock() {
return new Lock();
}

/**
* 获得锁,超时退出
* @param id
* @param timeout 超时时间(ms)
* @return
*/
public boolean lock(String id, int timeout) {

//这里的Jedis实际上是个代理。代理类JedisCallback,JedisFactoryBean
Jedis jedisProxy = JedisProxy.create();

long lock = 0;

long start = System.currentTimeMillis();

while (lock != 1) {
long now = System.currentTimeMillis();
//判断超时
if (timeout > 0 && now > start + timeout) {
return false;
}
long timestamp = now + EXPIRE * 1000 + 1;

try {
String key = String.format(LOCK, id);
lock = jedisProxy.setnx(key, String.valueOf(timestamp));
if (lock == 1) {
logger.info("设置redis锁key成功,lock key=" + key);
jedisProxy.expire(key, EXPIRE);
logger.info("设置redis锁key过期时间成功,lock key=" + key);
} else {
String s = jedisProxy.get(key);
Long lastLockTime = Long.parseLong(s);

//一个项目部署多个服务,锁可能已经被相同定时任务的其他进程获得,则直接返回false
if (jedisProxy.ttl(key)!=-1&&lastLockTime > System.currentTimeMillis()){
logger.info("redis锁已经被其他服务获得,lock key=" + key);
return false;
}
/**
* 如果上次锁定的时间已经过期,则清除key锁,以便定时任务能够启动
* 造成未能释放的原因主要是jedis.expire(key, EXPIRE);失败
* 或者是获取锁之后,由于程序错误或网络错误,unlock未被成功调用
*/
if (jedisProxy.ttl(key)==-1||lastLockTime < System.currentTimeMillis()) {
jedisProxy.del(key);
continue;
}
// this.wait(100);
Thread.sleep(100);
}
} catch (Exception e) {
logger.error("从redis获取定时任务锁错误,key="+String.format(LOCK, id), e);
return false;
}
}
return true;
}

/**
* 释放锁
* @param id
*/
public void unLock(String id) {

//这里的Jedis实际上是个代理。代理类JedisCallback,JedisFactoryBean
Jedis jedisProxy = JedisProxy.create();
String key = String.format(LOCK, id);
jedisProxy.del(key);
}
}

JedisProxy类

/**
* Jedis代理
*/
@Component
public class JedisProxy implements ApplicationContextAware {

private static volatile ApplicationContext ac;

/**
* 创建Jedis 代理
*
* @return
*/
public static Jedis create() {
return ac.getBean(Jedis.class);
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) {
if (ac != null) {
return;
}
synchronized (JedisProxy.class) {
if (ac != null) {
return;
}
ac = applicationContext;
}
}
}
原文地址:https://www.cnblogs.com/xmanblue/p/5301858.html