场景:
假如线程A获取分布式锁进入方法A,由于某种原因Hang住了 到了指定时间释放锁,这个时候线程B进入得到锁,这个时候线程B很顺利完成业务逻辑操作,然后释放掉锁,就在这个时候线程A开始继续往下执行代码,按照这个逻辑他最终会执行finally代码块 执行到释放锁的逻辑
那么这个时候如果锁的值一样,很有可能会释放掉已经获取锁的线程持有的那把锁。
那么该如何设计呢?
答案很简单,可以把锁的值设为UUID,保证唯一,这样每个线程的锁的值都是不一样的!
我们释放REDIS的锁 是通过执行LUA脚本实现的
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
调用的时候,锁的值是UUID的值。那为什么要设计为UUID的值,而不是随便来一个值呢?
String lockVal = UUID.randomUUID().toString();
public boolean unlock(String lockName, String lockVal) { log.info("释放redis锁 {}", lockVal); Object eval = redisTemplate.execute(unlockLuaScript, Lists.newArrayList(lockName), lockVal); if (eval != null) { ArrayList<Long> evalArr = (ArrayList<Long>) eval; boolean b = evalArr.get(0) == 1; if (b) { log.info("释放redis锁成功 {}", lockVal); return true; } } log.error("释放redis锁超时 {}", lockVal); return false; }
上面这段代码解释了为什么redis锁的值要设计成为UUID的uuid形式 因为假如redis业务逻辑时间执行的比较长,可能导致超时释放锁,那么另一线程获取锁,其执行完相关业务代码后,释放了锁。然后上一个线程执行完逻辑后,继续执行 (这个时候它是无锁的状态)但还是会去释放锁因为finally代码会最终执行!