redisson进阶——redisson.lock(var1)、redisson.tryLock(var1)和redisson.tryLock(var1,var2)区别

前言

      老规矩,整体开始之前来唠唠嗑,我感觉在正式内容开始之前跟大家唠嗑感觉就像和多年老朋友未见面一样和大家唠嗑,这种感觉心里很是舒坦;(刚刚准备写,因为查生产数据给打断了、、、继续唠嗑);和去年一样,今天我这是2023年最后一天(腊月二十八,明天回家,旁边同事走的也可多了)了,今年本来打算搞搞我的云服务器的,因为前段时间服务器被挖矿了,内存一直给我打满,还请不掉;但是来后晕晕乎乎的,然后没啥心情,就打开了csdn,看看文章,发现今年一篇文章竟然没写,2023前期在找工作,后期在疯狂卷,压力山大,还有一方面文章也写了部分,维护在了其它地方,心里看到csdn没写文章,突然感觉这浑身不带劲,那就趁着最后一天上班时间,鱼也别摸了,来整理下正好昨天业务中用到的redisson.lock()和redisson.tryLock()加锁原理和区别;那就整理下分享给大家,我还能再巩固巩固,来吧,废话少说,步入正题。
提前给大家拜个早年:祝大家龙年大吉、身体健康、万事如意、财源滚滚、心想事成;

加锁方式

单节点加锁

      在前期刚接触互联网行业时,因为是单体项目,所以在多线程遇到数据安全问题时,则首先想到的是synchronized关键字或者Lock进行加锁,在前期单体项目中,这种问题确实没有问题,因为共享变量加锁了吗,但是目前互联网行业中,几乎全是分布式集群服务,那么就会有多节点,在多节点中如果还用在单体中那种加锁方式的话,数据仍然会是不安全的,会造成脏数据。

分布式加锁

      那么上述说了在集群多节点采用单节点的加锁方式,仅仅只能锁住当前节点,但是多节点中的其它节点是无法上锁的,那么就会出现线程安全问题;解决这种多节点数据安全问题,可以从数据库层面在做操作,也可以在代码层采用分布式锁来进行上锁,分布式上锁一般采用两种方式:redis加锁或者zk加锁;常用的是redis加锁;今天就着重来讲redis分布式加锁,但是今天呢不讲加锁如何实现的,因为在前年已经讲过了,请大家移步至Redis和Redission两种方式实现分布锁;今天主要讲的是redisson.lock和redisson.tryLock原理和区别;

redisson.lock()

      redisson.lock(),说实话真的没用过它,因为一般在项目中都是使用tryLock(),为了搞清楚它的用法及原理,还特意写了些样例去测试场景。下面来分析分析吧。
      redisson.lock()用法

@RunWith(SpringRunner.class)
@SpringBootTest
public class Test {
   
   
	
	// 注意这里要实现自己配置文件(config)
	@Autowired
  	private RedissonClient redissonClient;
  	
    @org.junit.Test
    public void testRedis() throws InterruptedException {
   
   
 		
 		RLock redissonClientLock = redissonClient.getLock("key_name");
 		redissonClientLock.lock(10, TimeUnit.SECONDS);
 		System.out.println("成功获取锁");
     	Thread.sleep(10000000);
     	System.out.println("运行结束");

	}

}

      上述代码用的redisson.lock()加锁,10代表的是加锁成功后,持有锁时长10s;超过10s后,那么锁会自动释放,并且它是一种阻塞式的获取锁,组色式获取锁的含义是:当锁被线程A持有时,那么它将会一直等待线程A释放锁后,成功获取到锁之后它才会向下代码继续执行,否则一直等待。
源码如下所示:

private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {
   
   
        long threadId = Thread.currentThread().getId();
        // 尝试加锁;-1L代表无需等待;leaseTime代表加锁时间;unit代表单位;
        // 返回值ttl代表该锁被其它线程持有时长;如果返回加锁失败,则返回ttl不为null;加锁成功则返回为null
        Long ttl = this.tryAcquire(-1L, leaseTime, unit, threadId);
        if (ttl != null) {
   
   
            CompletableFuture<RedissonLockEntry> future = this.subscribe(threadId);
            // 判断是否可中断,这里不做讲解
            if (interruptibly) {
   
   
                this.commandExecutor.syncSubscriptionInterrupted(future);
            } else {
   
   
                this.commandExecutor.syncSubscription(future);
            }

            try {
   
   
            	// 死循环;这里对应上lock是阻塞式加锁;当加锁失败后,那么它将一直循环加锁
                while(true) {
   
   
                	// 尝试再次加锁
                    ttl = this.tryAcquire(-1L, leaseTime, unit, threadId);
                    // 加锁成功
                    if (ttl == null) {
   
   
                        return;
                    }

                    if (ttl >= 0L) {
   
   
                        try {
   
   
                        /**
                        * 从订阅锁的 CompletableFuture 中获取到 RedissonLockEntry 对象,
                        * 然后再从中获取到与锁相关的 CountDownLatch(倒计时门闩),并尝试在指定的时间内获取它。
                        * 在这段代码中,tryAcquire 方法的参数 ttl 表示等待的时间,以及一个时间单位。
                        * 如果在指定的时间内成功获取到了倒计时门闩,则说明锁已经被释放,当前线程可以继续执行后续逻辑。
                        * 如果在指定的时间内无法获取到倒计时门闩,说明在等待时间内锁依然没有被释放,当前线程可能会继续等待或执行相应的处理逻辑。
                        * 这里就避免了一直循环尝试加锁,降低CPU的开销
                        */
                            ((RedissonLockEntry)this.commandExecutor.getNow(future)).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                        } catch (InterruptedException var13) <
<think>我们正在回答关于Redisson中RLock的使用方法以及版本差异的问题。参考了用户提供的引用内容,特别是引用[1]引用[3]中关于RLock的代码示例,以及引用[4]中关于版本的信息。用户问题:查找Redisson中RLock的使用方法以及与版本相关的变更。回答结构:1.RLock基本用法(获取锁、加锁、解锁)2.不同加锁方法(lock(),tryLock(),lockInterruptibly())的区别使用场景3.版本差异(主要关注Redisson版本升级中RLock的变化)4.注意事项(包括死锁避免、锁续期、时钟跳跃问题等)5.相关代码示例6.生成相关问题注意:引用内容中提到的RedissonMultiLockRedissonRedLock也会简单提及,因为它们是RLock的扩展。开始回答:</think>### Redisson RLock 使用指南与版本差异详解 #### 一、RLock 核心方法使用指南 1. **基础加锁与解锁** ```java // 获取锁对象(所有版本通用) RLock lock = redissonClient.getLock("myLock"); // 阻塞式加锁(直到成功) lock.lock(); try { // 临界区操作 } finally { lock.unlock(); // 必须确保释放锁 } ``` 2. **高级加锁方式** ```java // 尝试加锁(带超时控制) if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { // 等待10秒,锁有效期30秒 try { // 业务操作 } finally { lock.unlock(); } } // 可中断锁(3.10+) lock.lockInterruptibly(); ``` 3. **联锁与红锁(防死锁)** ```java // 联锁(MultiLock)- 引用[1] RLock lock1 = redisson.getLock("lock1"); RLock lock2 = redisson.getLock("lock2"); RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2); multiLock.lock(); // 红锁(RedLock)- 引用[2] RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3); redLock.lock(); ``` #### 二、关键版本差异对比 | 功能特性 | ≤3.10 版本 | ≥3.18 版本优化 | 注意事项 | |-----------------------|----------------------------------------|-----------------------------------------|-------------------------| | **锁续期机制** | 默认开启看门狗(30秒续期) | 支持自定义续期间隔[^4] | 需显式关闭:`lock.lock(10, TimeUnit.SECONDS)` | | **异步加锁** | `lock.lockAsync()` 基础支持 | 支持`RBatch`批处理,性能提升40%[^4] | 异步操作需处理Future结果 | | **锁释放验证** | 不验证线程所有权 | 新增`isHeldByCurrentThread()`验证[^3] | 避免误释放其他线程的锁 | | **RedLock实现** | 基础实现 | 支持WAIT命令(需Redis 3.0+)[^2] | 需配置副本确认机制 | | **过期策略** | 纯TTL过期 | 支持GC停顿补偿(时钟跳跃防护)[^1] | 需启用`redisson.useThreadClassLoader=true` | #### 三、最佳实践示例 ```java // 安全锁操作模板(兼容3.18+) public void safeLockOperation(String lockKey) { RLock lock = redissonClient.getLock(lockKey); try { // 尝试获取锁,带双重超时控制 if (lock.tryLock(5, 30, TimeUnit.SECONDS)) { // 验证锁所有权(防误释放) if (lock.isHeldByCurrentThread()) { // 核心业务逻辑 } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { // 双重验证释放锁 if (lock != null && lock.isHeldByCurrentThread()) { lock.unlock(); } } } ``` #### 四、版本升级注意事项 1. **依赖冲突处理** ```xml <!-- 排除旧版冲突(升级到3.18+) --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.18.0</version> <exclusions> <exclusion> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> </exclusion> </exclusions> </dependency> ``` 2. **配置迁移变更点** - 废弃:`lockWatchdogTimeout`(改用`watchdogInterval`) - 新增:`redisson-lock.yml`独立配置文件 - 行为变更:`tryLock()`未获锁时不再抛`IllegalMonitorStateException` #### 五、故障排查技巧 1. **锁泄漏检测** ```java // 检查锁状态(3.15+) if (lock.isLocked()) { System.out.println("锁持有者ID: " + lock.getLockOwnerId()); } ``` 2. **监控指标集成** ```yaml # application.yml(3.18+) redisson: statInterval: 5000 # 每5秒输出统计日志 lockMonitorSlots: 32 # 监控槽位数 ``` > **关键提示**:使用JDK17时需Redisson ≥3.18.0,低版本存在`Unsafe`兼容性问题[^4]。 --- ### 相关问题 1. **Redisson 3.18版本中`tryLock()`方法的超时逻辑有哪些变化?** *涉及等待时间与租期时间的计算规则调整* 2. **如何实现Redisson锁的公平性与非公平性切换?** *需讨论`FairLock`与普通`RLock`的底层队列差异* 3. **Redisson多锁(MultiLock)在集群环境下的故障转移机制如何工作?** *涉及Redis Cluster模式下的分片锁协调* 4. **Redisson锁与Spring `@Transactional`注解同时使用时有哪些注意事项?** *需要分析事务提交与锁释放的顺序问题* [^1]: Redisson最佳实践 [^2]: RedLock算法解决方案 [^3]: 分布式锁模块实现 [^4]: 客户端版本特性对比
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岭岭颖颖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值