获取锁超自动发现,方法有所改变,不再是使用lock.lock(),而是使用lock.tryLock()

public static void main(String[] args) throws Exception {
    	//构建一个配置信息对象
        Config config = new Config();
        config.useClusterServers()
                //定时扫描连接信息 默认1000ms
                .setScanInterval(2000)
                .addNodeAddress("redis://127.0.0.1:7001");
		//因为Redisson 是基于redis封装的一套便于复杂操作的框架
		//所以这里构建对象肯定是创建一些与redis的连接
        RedissonClient redisson = Redisson.create(config);
		//这里是重点 获取锁,这也是重点分析的地方
        RLock lock = redisson.getLock("lock");
        //尝试获取锁,会等待100S,如果超过了等待时间就会返回false
        //如果获取到了锁,那么最多持有10S,超过10S会释放锁
        boolean result = lock.tryLock(100, 10, TimeUnit.SECONDS);
        //释放锁
        lock.unlock();
    }

 

@Override
    public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
        long time = unit.toMillis(waitTime);
        long current = System.currentTimeMillis();
        final long threadId = Thread.currentThread().getId();
        //首先进来就尝试获取锁,跟之前的lock.lock()方法逻辑一样,调用lua脚本,尝试获取锁
        //或者是重入锁,将锁对应的map 中的唯一标志 value + 1 
        //其实不一样的再后面的代码
        //
        Long ttl = tryAcquire(leaseTime, unit, threadId);
        // lock acquired
        if (ttl == null) {
            return true;
        }
           //减去尝试获取锁的时间
        //假设尝试获取锁 花费了1S,那么time -= 1 ,就是 99S
        time -= (System.currentTimeMillis() - current);
           //如果超时了就标记尝试获取锁失败
            //失败了要干嘛?肯定要将一些环节数据 清除
        if (time <= 0) {
            acquireFailed(threadId);
            return false;
        }
        
        current = System.currentTimeMillis();
        final RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
        if (!await(subscribeFuture, time, TimeUnit.MILLISECONDS)) {
            if (!subscribeFuture.cancel(false)) {
                subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
                    @Override
                    public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
                        if (subscribeFuture.isSuccess()) {
                            unsubscribe(subscribeFuture, threadId);
                        }
                    }
                });
            }
            acquireFailed(threadId);
            return false;
        }

        try {
            time -= (System.currentTimeMillis() - current);
            if (time <= 0) {
                acquireFailed(threadId);
                return false;
            }
            //进入死循环,不断的尝试获取锁
            //不断的计算 尝试获取锁花费的时间,以及等待时间
            //计算是否超时,如果超时,就返回获取失败
        
            while (true) {
                long currentTime = System.currentTimeMillis();
                ttl = tryAcquire(leaseTime, unit, threadId);
                // lock acquired
                if (ttl == null) {
                    return true;
                }

                time -= (System.currentTimeMillis() - currentTime);
                if (time <= 0) {
                    acquireFailed(threadId);
                    return false;
                }

                // waiting for message
                currentTime = System.currentTimeMillis();
                if (ttl >= 0 && ttl < time) {
                    getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                } else {
                    getEntry(threadId).getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);
                }

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

超时锁的自动释放,其实就是我们自己设置的leaseTime 

private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, final long threadId) {
        //指定了leaseTime 就会走这块代码
        if (leaseTime != -1) {
            //直接执行lua脚本
            //然后不会给RFuture 添加一个监听器,开启一个定时的去刷新过期时间的任务
            //意思就是我们设置的过期时间就是一次性的,不会去尝试延长时间
            return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
        }
        
        RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
        ttlRemainingFuture.addListener(new FutureListener<Long>() {
            @Override
            public void operationComplete(Future<Long> future) throws Exception {
                if (!future.isSuccess()) {
                    return;
                }

                Long ttlRemaining = future.getNow();
                // lock acquired
                if (ttlRemaining == null) {
                    scheduleExpirationRenewal(threadId);
                }
            }
        });
        return ttlRemainingFuture;
    }

其实看了源码,超时怎么释放?其实依靠的还是redis 本身自身的机制,过期时间,只是这里我们如果自己设置了leaseTime,那么我们Redisson Client 就不会去尝试开启定时任务,每隔一段时间去刷新lock的过期时间。其实和lock.lock()的区别大致就在这一小块 

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐