分布式锁
通过2个原子性的命令setnx
getset
还有
expire
设有效期
del
删除
第一版分布式锁
版本1
public void 分布式锁版本1(){
Long setnxResult = RedisShardedPoolUtil.setnx(key, 现在时间);
//mark 如果允许到这 tomcat重启了 锁还没有加期限 这个锁就永远不会被释放了 没人可以再得到锁了
//如果是正常关闭 delLock能解决
if(setnxResult != null && setnxResult.intValue() == 1){
//如果返回值是1,代表设置成功,获取锁 closeOrder还会设定过期时间 完成后删除锁
RedisShardedPoolUtil.expire(key,50);//有效期 50秒,防止死锁
//业务执行
RedisShardedPoolUtil.del(key); //释放锁
}
}
但是如果得到锁,还没设有效期 tomcat就重启了,这个锁就永远没人能得到了
Redis 2.8 版本中作者加入了 set 指令的扩展参数,使得 setnx 和 expire 指令可以一起执行
set lock:codehole true ex 5 nx
为了防止这种情况
//tomcat 正常关闭前会调用
@PreDestroy
public void delLock(){
//释放锁
RedisShardedPoolUtil.del(key);
}
虽然可以@PreDestroy让tomcat关闭前调用,但是tomcat不一定是正常关闭,如果要好多锁需要释放,tomcat就会很慢
第二版分布式锁
第二版
第二版就是利用了setnx进去的过期时间,如果这个值过期了 也算拿到锁
public void 第二版() {
Long setnxResult = RedisShardedPoolUtil.setnx(key, 现在时间);
//顺利拿到锁
if (setnxResult != null && setnxResult.intValue() == 1) {
//业务
RedisShardedPoolUtil.del(key); //释放锁
return;
}
//未获取到锁,继续判断,判断时间戳,看是否可以重置并获取到锁
String oldValue = RedisShardedPoolUtil.get(key);
//再看这个锁没有了,或者那个锁超时了
if (oldValue != null && System.currentTimeMillis() > Long.parseLong(oldValue)) {
//再次用当前时间戳getset。
String getSetResult = RedisShardedPoolUtil.getSet(key, 现在时间);
//当key没有旧值时,即key不存在时,返回nil ->获取锁
// 旧值就是我们刚才看到的过期的那个 ->获取锁
if (getSetResult == null || StringUtils.equals(oldValue, getSetResult)) {
//业务
RedisShardedPoolUtil.del(key); //释放锁
return;
}
}
//没有获取到分布式锁:
}
第三版分布式锁 用Redssion
@Autowired
private RedissonManager redissonManager;
// @Scheduled(cron="0 */1 * * * ?")
public void 第三版(){
RLock lock = redissonManager.getRedisson().getLock(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
boolean getLock = false;
try {
//等待0秒(只能填0),最多持有锁50秒
getLock = lock.tryLock(0, 50, TimeUnit.SECONDS);
if(getLock){
log.info("Redisson获取到分布式锁:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
// 业务代码
}else{
log.info("Redisson没有获取到分布式锁:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
}
} catch (InterruptedException e) {
log.error("Redisson分布式锁获取异常",e);
} finally {
//如果拿到锁了就要释放
if(getLock){
lock.unlock();
log.info("Redisson分布式锁释放锁");
}
}
}