RLock rLock = redissonClient.getLock("lockName");// 可以看做是获取一个连接
try {
// 尝试加锁 愿意等待的时长 waitTime ; 加锁成功后自动释放锁的时长 leaseTime,大于0时不论加锁业务是否处理完毕都会释放锁
boolean locked = rLock.tryLock(1000, 2000, TimeUnit.MILLISECONDS);// 尝试加锁
if(locked){
// todo 加锁成功需要处理的业务处理
}else{
// todo 加锁失败需要处理的业务
}
}catch (Exception e) {//
throw e; // 加锁失败 和 业务处理失败后 需要做的事情
} finally {
try{
rLock.unlock();// 这个很要命 手动释放锁 unlock 异常后是否需要
}catch(Exception e){
// 释放锁失败 要做的处理(忽略异常 还是 继续抛出异常,还是 强制释放锁)
}
}
一、先做点解释
1、参数
waitTime 为了获取锁愿意等待的时长 <= 0 不愿意等待,即没有获取到锁时直接返回false
leaseTime 加锁成功后自动释放锁的时长,>0 时 不论锁定的业务是否执行完毕都会在这个时间到期时释放锁---这个很要命;=-1表示这个锁不会自动释放必须手动释放,看门狗每10秒(默认配置)延期一次锁(实际是重置锁的过期时间为30秒:默认配置)
2、上图伪代码仅供参考
二、结论
1、根据自身业务 谨慎并合理设置 waitTime 和 leaseTime 值 ;
2、finally 中一定要 手动释放锁 rLock.unlock(); ---锁定的资源在业务处理完毕后尽快释放,不论是否设置了自动释放锁;
三、加锁的lua脚本
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"return redis.call('pttl', KEYS[1]);"
KEYS[1]=lockName,ARGV[2]=hash中的key=redisson客户端节点id+线程id,ARGV[1]=锁的过期时间