但考虑到,可能在业务执行时间长的情况下,正好锁的存活时间超时了,那么线程2有可能也获取到锁了,然后线程一执行完所有任务后,remove key(锁),导致把线程2的锁误删了,这就很严重。
有人说,可以在删除前get key,对比锁的值是否相等,但一般情况下redis的 get 和remove是分开执行的,中间的时间间隔还是会出现上面说的误删情况,所以可以使用lua脚本,redis 执行lua脚本也是原子的,所以更合适.
private static final Long lockReleaseOK = 1L;
static String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";// lua脚本,用来释放分布式锁
public static boolean releaseLock(String key ,String lockValue){
if(key == null || lockValue == null) {
return false;
}
try {
Jedis jedis = getJedisPool().getResource();
Object res =jedis.eval(luaScript,Collections.singletonList(key),Collections.singletonList(lockValue));
jedis.close();
return res!=null && res.equals(lockReleaseOK);
} catch (Exception e) {
return false;
}
}
当然redis实现分布式锁不是完美的,假设在主从节点情景下,redis master同步数据到从库,中途有很小延迟,也会少见出现获取锁不正常问题