redisson实现分布锁的源码分析、逻辑图

导读:本篇文章讲解 redisson实现分布锁的源码分析、逻辑图,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

文章目录

此处只以RLock.java的void lock(long leaseTime, TimeUnit unit)方法为例。
本文按代码逻辑顺序进行整理分析。

@Override
 public void lock(long leaseTime, TimeUnit unit) {
        try {
            lockInterruptibly(leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
@Override
    public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {
        long threadId = Thread.currentThread().getId();
        //尝试获得锁,此方法也是redisson加锁的重点
        Long ttl = tryAcquire(leaseTime, unit, threadId);
        // 获得锁
        if (ttl == null) {
            return;
        }
		//订阅锁释放的消息。此处redis的机制如何实现的?我还没搞明白
        RFuture<RedissonLockEntry> future = subscribe(threadId);
        commandExecutor.syncSubscription(future);

        try {
            while (true) {
                ttl = tryAcquire(leaseTime, unit, threadId);
                // lock acquired
                if (ttl == null) {
                    break;
                }

                // 等到锁释放
                if (ttl >= 0) {
                    getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                } else {
                    getEntry(threadId).getLatch().acquire();
                }
            }
        } finally {
	        //取消订阅锁释放信息
            unsubscribe(future, threadId);
        }
    }
 private Long tryAcquire(long leaseTime, TimeUnit unit, long threadId) {
		 /**
		 *此处调用了异步方法,然而用同步方式返回给上一段代码。我不明白这样的意义何在?
		 */
        return get(tryAcquireAsync(leaseTime, unit, threadId));
    }
private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, final long threadId) {
		//有传入leaseTime
        if (leaseTime != -1) {
            return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
        }
        //由于未设置leaseTime,所以用redisson默认的30秒锁超时
        RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(LOCK_EXPIRATION_INTERVAL_SECONDS, TimeUnit.SECONDS, 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;
    }

tryLockInnerAsync()方法是redisson核心逻辑

<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
        internalLockLeaseTime = unit.toMillis(leaseTime);
        //使用 EVAL 命令执行 Lua 脚本获取锁
		//KEYS[1] :需要加锁的key,这里需要是字符串类型。
		//ARGV[1] :锁的超时时间,防止死锁
		//ARGV[2] :锁的唯一标识 id(UUID.randomUUID()) + ":" + threadId
        return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
                  "if (redis.call('exists', KEYS[1]) == 0) then " +/**判断锁是否存在*/
                      "redis.call('hset', 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); " +/**value加1*/
                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +/**重新设置超时时间*/
                      "return nil; " +
                  "end; " +
                  "return redis.call('pttl', KEYS[1]);",
                    Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
    }

上面的代码就是redisson进行加锁的主要代码。
下面是根据代码所画出的流程图。
这里写图片描述

本人理解可能会有偏差,错误之处,望各位指教。



  • 文章是个人知识点整理总结,如有错误和不足之处欢迎指正。
  • 如有疑问、或希望与笔者探讨技术问题(包括但不限于本章内容),欢迎添加笔者微信(o815441)。请备注“探讨技术问题”。欢迎交流、一起进步。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/69884.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!