Redisson 源码初探(九)ReadWriteLock 读写锁

本文深入探讨Redisson的ReadWriteLock,重点分析加锁、释放锁的Lua脚本,以及读写锁的可重入性和并发控制。讨论了读锁、写锁的实现,包括加锁逻辑、续租机制、读写锁转换的条件以及锁释放的步骤。揭示了读写锁在多线程环境中的工作原理和潜在问题,如写锁饥饿现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

读写锁得概念我们就不再赘述了

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);
        ReadWriteLock readWriteLock = redisson.getReadWriteLock("lock");
        readWriteLock.readLock().lock();
        readWriteLock.writeLock().lock();
        //释放锁
        readWriteLock.readLock().unlock();
        readWriteLock.writeLock().unlock();
    }

我们先来看看读锁,RedissonReadLock ,其实我们大概现在都知道了,加锁得逻辑最主要还是去理解lua脚本,RedissonReadLock 覆盖了一些主要得方法,我们主要研究 加锁 释放锁 以及renew续约的lua脚本

我们直接来看RedissonReadLock 加锁的lua脚本

还是研究参数代表的意义

KEY[1] = 锁的名称

KEY[2] = getReadWriteTimeoutNamePrefix(threadId) {lockName};UUID_01:ThreadId_01 : rwlock_timeout

ARGV[1] = internalLockLeaseTime

ARGV[2] = getLockName(threadId)  UUID_01:threadId

ARGV[3] = getWriteLockName(threadId)  UUID_01:ThreadId:write

读锁的lua脚本

最简单的加锁逻辑是非常的清晰的,但是我们肯定是要分析复杂的逻辑对吧,比如可重入性

(1)连续加2次读锁

(2)连续加2次写锁

(3)先读锁,后写锁

(4)先写锁,后读锁

这几种情况是如何运转的? 也就是研究锁的可重入性


    @Override
    <T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
        internalLockLeaseTime = unit.toMillis(leaseTime);

        return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
                                  //hget key mode  就是代表从key对应的map数据结构中获取mode对应的值
                                "local mode = redis.call('hget', KEYS[1], 'mode'); " +
                                "if (mode == false) then " +
                                    //设置模式为读模式
                                  "redis.call('hset', KEYS[1], 'mode', 'read'); " +
                                    //设置读锁持有的线程名称
                                  "redis.call('hset', KEYS[1], ARGV[2], 1); " +
                                    //两个点是什么意思? 就是字符串拼接,将KEY[2]:1 生成新的字符串
                                  "redis.call('set', KEYS[2] .. ':1', 1); " +
                                    //设置KEY[1] KEY[2]的过期时间
                                  "redis.call('pexpire', KEYS[2] .. ':1', ARGV[1]); " +
                                  "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                                  "return nil; " +
                                "end; " +
                                //锁的可重入性逻辑脚本 ,不管之前是读还是写都将其 +1 
                                "if (mode == 'read') or (mode == 'write' and redis.call('hexists', KEYS[1], ARGV[3]) == 1) then " +
                                    //将对应的值 +1
                                  "local ind = redis.call('hincrby', KEYS[1], ARGV[2], 1); " +                             //设置 该次加锁对应timeout key 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值