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、 boolean locked = rLock.tryLock(10000L, -1, TimeUnit.MILLISECONDS);  // 假如主线程执行到这里出现某种未知原因,主线程中断了,但是加锁的子线程竟然成功然后并启动看门狗自动延期锁;
2、 rLock.unlock();// 主线程挂掉时子线程加锁没有完成,这里释放锁无效;

死锁了。 怎么办? 幸好有 forceUnlock
rLock.forceUnlock(); // 强制释放锁  怎么用?什么场景下使用(程序中怎么判断死锁了)?

一、先做点解释

1、参数 

        waitTime  为了获取锁愿意等待的时长 <= 0 不愿意等待,即没有获取到锁时直接返回false

leaseTime 加锁成功后自动释放锁的时长:

        >0 时 不论锁定的业务是否执行完毕都会在这个时间到期时释放锁---这个很要命(一定不会死锁);肯能会存在线程1执行业务没有完毕,锁自动释放了,线程2获取到锁执行了业务,锁失效了;

        =-1表示这个锁不会自动释放必须手动释放(可能会死锁),看门狗每10秒(默认配置)延期一次锁(实际是重置锁的过期时间为30秒:默认配置)

2、上图伪代码仅供参考

二、结论

谨慎并合理设置

        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]=锁的过期时间

四、记录一个问题:

执行加锁时遇到一个异常 WRONGTYPE Operation against a key holding the wrong kind of value

具体异常信息:

org.redisson.client.RedisException: WRONGTYPE Operation against a key holding the wrong kind of value.
 channel: [xxxx] 
 command: (HEXISTS), params: [LOCK_NAME, XXXXX]

发生问题的地方:执行加锁脚本走都第二个分支时 执行 redis.call('hexists', KEYS[1], ARGV[2]) == 1 命令有redis服务端抛出异常;

原因:针对LOCK_NAME ,服务1 中使用了 redisson 的锁,服务2中 程序员自己实现了一个分布式锁;

结论:不要制造不必要的轮子