Redission-tryLock源码解析

时间:2025-03-22 09:25:50

Redisson的加锁方法有两个,tryLock和lock,使用上的区别在于tryLock可以设置锁的过期时长leaseTime和等待时长waitTime,核心处理的逻辑都差不多

    public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
        long time = (waitTime);
        long current = ();
        long threadId = ().getId();

        // 尝试获取锁,如果没取到锁,则返回锁的剩余超时时间 
        Long ttl = tryAcquire(waitTime, leaseTime, unit, threadId);
        // lock acquired

        // ttl为null,说明可以抢到锁了,返回true 
        if (ttl == null) {
            return true;
        }
        

        // 如果waitTime已经超时了,就返回false,代表申请锁失败 
        time -= () - current;
        if (time <= 0) {
            acquireFailed(waitTime, unit, threadId);
            return false;
        }
        
        current = ();

        /**
        订阅锁释放事件,并通过 await 方法阻塞等待锁释放,有效的解决了无效的锁申请浪费资源的问题:
    基于信息量,当锁被其它资源占用时,当前线程通过 Redis 的 channel 订阅锁的释放事件
    一旦锁释放会发消息通知待等待的线程进行竞争.
        */
        RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
        if (!(time, )) {
            if (!(false)) {
                ((res, e) -> {
                    if (e == null) {
                        unsubscribe(subscribeFuture, threadId);
                    }
                });
            }
            acquireFailed(waitTime, unit, threadId);
            return false;
        }

        try {

            //如果获取锁的耗时超过最大等待时间,加锁失败
            time -= () - current;
            if (time <= 0) {
                acquireFailed(waitTime, unit, threadId);
                return false;
            }

            //在最大等待时间内循环获取锁
            while (true) {
                long currentTime = ();
                ttl = tryAcquire(waitTime, leaseTime, unit, threadId);
                // lock acquired
                if (ttl == null) {
                    return true;
                }

                time -= () - currentTime;
                if (time <= 0) {
                    acquireFailed(waitTime, unit, threadId);
                    return false;
                }

                // waiting for message
                currentTime = ();

                // waiting for message,等待解锁消息
                if (ttl >= 0 && ttl < time) {
                    ().getLatch().tryAcquire(ttl, );
                } else {
                    ().getLatch().tryAcquire(time, );
                }

                time -= () - currentTime;
                if (time <= 0) {
                    acquireFailed(waitTime, unit, threadId);
                    return false;
                }
            }
        } finally {
            //取消订阅消息
            unsubscribe(subscribeFuture, threadId);
        }
//        return get(tryLockAsync(waitTime, leaseTime, unit));
    }

Redission分布式锁原理_知知之之的博客-****博客_redission实现分布式锁原理原理源码中加锁lua代码if (('exists', KEYS[1]) == 0) then ('hset', KEYS[1], ARGV[2], 1); ('pexpire', KEYS[1], ARGV[1]); return nil; end;if (('hexists', KEYS[1], ARGV[2]) == 1) thenhttps:///weixin_35973945/article/details/124151830

需要特别注意的是,RedissonLock 同样没有解决 节点挂掉的时候,存在丢失锁的风险的问题。而现实情况是有一些场景无法容忍的,所以 Redisson 提供了实现了redlock算法的 RedissonRedLock,RedissonRedLock 真正解决了单点失败的问题,代价是需要额外的为 RedissonRedLock 搭建Redis环境。

所以,如果业务场景可以容忍这种小概率的错误,则推荐使用 RedissonLock, 如果无法容忍,则推荐使用 RedissonRedLock。