Redisson的RLock默认可重入,需同一线程、同一锁名、同一RedissonClient实例才能生效;连续调用tryLock()不报错不等于可重入成功,必须确保线程一致且正确释放(调用unlock()次数等于加锁次数)。

Redisson 的 RLock 默认就是可重入的,不需要额外配置,但必须用对 API 才能真正生效。
为什么 tryLock() 调用两次不报错 ≠ 可重入成功
很多人在方法里连续调用 lock.tryLock(3, 10, TimeUnit.SECONDS) 两次,发现没抛异常,就以为“可重入了”。其实这只是因为第一次加锁成功后,锁还持有,第二次 tryLock() 在等待时间内直接返回 true(Redisson 内部做了线程级重入计数),但如果你没用同一个 RLock 实例、或跨线程/跨请求使用,重入就会失效。
关键点:
-
RLock的可重入性基于「当前线程 + 锁名 + RedissonClient 实例」三者绑定 - 每次
redissonClient.getLock("key")返回的是逻辑上同一把锁,但对象引用不同 —— 重入判断不看引用,看线程 ID 和 Redis 中存储的锁持有信息 - 如果在异步线程(如
@Async)中尝试重入,会失败,因为线程变了
RLock 可重入的正确写法示例
下面是在同一个同步上下文中多次获取同一把锁的典型用法:
RLock lock = redissonClient.getLock("order:pay:123");
try {
// 第一次获取锁(阻塞等待最多 3 秒,持有 30 秒)
boolean acquired = lock.tryLock(3, 30, TimeUnit.SECONDS);
if (!acquired) throw new IllegalStateException("lock failed");
<pre class="brush:php;toolbar:false;">// 同一线程内再次 tryLock → 成功,重入计数 +1
boolean reentrant = lock.tryLock(0, 30, TimeUnit.SECONDS); // waitTime=0 表示不等待,立即返回
// 执行业务:比如查库存 → 扣减 → 更新订单状态
processOrder();} finally { // 必须调用 unlock() 直到重入计数归零才真正释放 if (lock.isHeldByCurrentThread()) { lock.unlock(); // 第一次调用只减计数 lock.unlock(); // 第二次调用才真正删除 Redis key } }
注意:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 不能用
lock.lock()(无参)替代tryLock(),它不支持超时控制,容易导致死锁 - 务必检查
isHeldByCurrentThread()再解锁,避免解锁别人持有的锁 - 不要在 finally 块外提前调用
unlock(),否则可能释放不完整
Spring Boot 3 中集成 Redisson 的配置陷阱
Spring Boot 3 默认启用 Jakarta EE 9+,而老版本 redisson-spring-boot-starter(如 3.17.x)依赖 javax.* 包,会导致启动失败或 RLock 不可重入(类加载冲突)。
必须确认以下三点:
- 使用
redisson-spring-boot-starter≥3.23.4(2026 年主流稳定版) -
spring-boot-starter-data-redis底层用的是 Lettuce,不是 Jedis(Redisson 不兼容 Jedis) - application.yml 中的
spring.redis.redisson.config必须是合法 YAML 多行字符串,开头带|,且缩进一致;漏掉管道符或缩进错位会导致RedissonClient初始化为 null,getLock()返回的锁实际无效
可重入锁在真实场景中的边界问题
可重入解决的是「同一线程反复进入临界区」的问题,但它不解决以下情况:
- 跨服务调用:A 服务加锁后调用 B 服务,B 服务无法继承 A 的锁上下文
- 异步任务:@Async 方法或线程池中新开线程,即使共享同一
RLock实例,也无法重入(线程 ID 不同) - 锁续期失效:如果业务执行时间超过
leaseTime且未开启看门狗(默认开启),锁会被自动释放,后续重入判定失效
真正容易被忽略的是:Redisson 的看门狗机制(watchdog)依赖 Netty 定时任务,若应用线程池耗尽或 GC 暂停过长,可能导致续期失败 —— 这时候看似“可重入”,实则锁已丢失。生产环境建议显式设置 leaseTime 为合理上限,并配合业务超时兜底。

















