Spring Boot3 Redisson 项目地址
https://gitee.com/supervol/loong-springboot-study
(记得给个start,感谢)
Redisson 介绍
在分布式系统中,多节点部署的应用对共享资源(如数据库记录、缓存键、文件)的并发访问需要分布式锁来保证互斥性,避免数据不一致问题。Spring Boot 3 生态中,Redisson 是实现分布式锁的主流方案之一 —— 它基于 Redis 封装了完整的分布式锁功能,解决了原生 Redis 实现锁的诸多痛点(如手动续期、不可重入、释放他人锁等),提供了高可用、易扩展的分布式锁能力。
Redisson 核心
1. 为什么需要分布式锁
单机应用中,synchronized
或 java.util.concurrent.locks.Lock
可解决并发问题,但分布式系统中多节点共享资源时,单机锁失效(各节点内存独立),需跨节点的 “全局锁”:
- 核心需求:互斥性(同一时间仅一个节点持有锁)、安全性(避免死锁)、可用性(锁服务不宕机)、重入性(同一线程可重复获取锁)、公平性(可选,按请求顺序获取)。
- 原生 Redis 痛点:需手动实现
setNx
+expire
原子操作、手动处理锁续期、无法原生支持重入、可能释放他人锁,而 Redisson 封装了这些细节。
2. Redisson 是什么
Redisson 是基于 Redis 的 Java 分布式客户端,不仅提供 Redis 基础操作(如字符串、哈希、列表),还内置了大量分布式场景工具类,核心能力包括:
- 分布式锁(可重入锁、公平锁、读写锁等);
- 分布式集合(分布式 Map、Set、Queue);
- 分布式信号量、计数器、限流器;
- 支持 Redis 单机、集群、哨兵、主从等所有部署模式。
其中,分布式锁是 Redisson 最核心的功能,它通过 Redis 的 Hash
数据结构和 Lua 脚本保证锁的原子性,同时提供 “看门狗(Watch Dog)” 机制解决锁续期问题。
Redisson 使用
Redisson 提供多种分布式锁类型,可重入锁(RLock) 是最常用的基础锁,其他锁(公平锁、读写锁等)均基于其扩展。
1. 可重入锁(RLock)
可重入锁支持同一线程多次获取锁(解决 “自己锁自己” 的问题),且内置 Watch Dog 自动续期 机制,避免业务未执行完锁已过期。
(1)核心 API
方法 | 功能说明 |
---|---|
lock() | 阻塞获取锁,默认启用 Watch Dog(leaseTime=-1),直到获取成功 |
lock(long leaseTime, TimeUnit unit) | 带过期时间的锁,leaseTime 后自动释放,禁用 Watch Dog |
tryLock() | 非阻塞获取锁,立即返回 true (成功)或 false (失败) |
tryLock(long waitTime, long leaseTime, TimeUnit unit) | 带等待时间的非阻塞锁: - waitTime :获取锁的最大等待时间(超时返回 false )- leaseTime :锁的过期时间(0 或 -1 启用 Watch Dog) |
unlock() | 释放锁,必须在 finally 中调用,避免死锁 |
isHeldByCurrentThread() | 判断当前线程是否持有锁,避免释放他人锁 |
(2)代码示例
生产环境中优先使用 tryLock
避免无限阻塞,同时在 finally
中安全释放锁:
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class OrderService {@Autowiredprivate RedissonClient redissonClient;// 分布式锁的 Key(需保证业务唯一性,如“订单创建_用户ID”)private static final String LOCK_KEY = "order:create:%s";/*** 创建订单(分布式锁保护)* @param userId 用户ID(用于生成唯一锁Key)*/public void createOrder(Long userId) {RLock lock = null;try {// 1. 生成唯一锁Key(按用户ID区分,避免锁冲突)String lockKey = String.format(LOCK_KEY, userId);// 2. 获取可重入锁lock = redissonClient.getLock(lockKey);// 3. 尝试获取锁:等待3秒,持有5秒(若5秒内未释放,锁自动过期)boolean isLocked = lock.tryLock(3, 5, TimeUnit.SECONDS);if (!isLocked) {// 4. 获取锁失败,返回友好提示throw new RuntimeException("当前操作过频繁,请稍后再试");}// 5. 获取锁成功,执行核心业务(如创建订单、扣减库存)System.out.println("获取锁成功,执行订单创建逻辑...");// 模拟业务耗时(如2秒)TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException("订单创建失败");} finally {// 6. 安全释放锁:仅释放当前线程持有的锁if (lock != null && lock.isHeldByCurrentThread()) {lock.unlock();System.out.println("锁释放成功");}}}
}
2. Watch Dog 自动续期
当 leaseTime
未设置(或设为 -1)时,Redisson 会启动 Watch Dog 机制,解决 “业务未执行完锁已过期” 的问题:
- 原理:Watch Dog 是一个后台线程,在锁快过期时(默认剩余 10 秒)自动将锁的过期时间延长至 30 秒;
- 默认配置:锁默认过期时间 30 秒,续期间隔 10 秒;
- 禁用场景:若手动设置
leaseTime
(如 5 秒),Watch Dog 会失效,锁会在leaseTime
后强制释放,需确保leaseTime
大于业务执行时间。
3. 其他常用锁类型
Redisson 提供多种锁类型,满足不同分布式场景需求:
(1)公平锁(RedissonFairLock)
按请求顺序获取锁,避免 “饥饿问题”(某些线程长期获取不到锁),适用于对公平性要求高的场景(如秒杀排队)。使用示例:
// 获取公平锁(替换 getLock 为 getFairLock)
RLock fairLock = redissonClient.getFairLock("order:create:1001");
try {if (fairLock.tryLock(3, 5, TimeUnit.SECONDS)) {// 执行公平锁保护的业务逻辑}
} finally {if (fairLock != null && fairLock.isHeldByCurrentThread()) {fairLock.unlock();}
}
(2)读写锁(RReadWriteLock)
读锁共享,写锁互斥,适用于 “读多写少” 的场景(如商品详情查询、库存更新),提高并发效率:
- 读锁(共享):多个线程可同时获取读锁,互不阻塞;
- 写锁(互斥):仅一个线程可获取写锁,且写锁与读锁互斥。
使用示例:
// 获取读写锁
RReadWriteLock rwLock = redissonClient.getReadWriteLock("product:info:1001");// 1. 读操作(获取读锁)
RLock readLock = rwLock.readLock();
try {readLock.lock(5, TimeUnit.SECONDS);System.out.println("获取读锁,查询商品详情..."); // 多个线程可同时执行
} finally {readLock.unlock();
}// 2. 写操作(获取写锁)
RLock writeLock = rwLock.writeLock();
try {writeLock.lock(5, TimeUnit.SECONDS);System.out.println("获取写锁,更新商品库存..."); // 仅一个线程执行
} finally {writeLock.unlock();
}
(3)联锁(RMultiLock)
需同时获取多个锁,全部获取成功才继续执行,适用于 “多资源协同锁定” 场景(如转账需同时锁定付款方和收款方账户)。使用示例:
// 1. 获取两个独立的锁
RLock lock1 = redissonClient.getLock("account:lock:1001"); // 付款方账户锁
RLock lock2 = redissonClient.getLock("account:lock:1002"); // 收款方账户锁// 2. 创建联锁(需全部锁获取成功才生效)
RMultiLock multiLock = new RedissonMultiLock(lock1, lock2);try {// 3. 尝试获取联锁(等待3秒,持有5秒)if (multiLock.tryLock(3, 5, TimeUnit.SECONDS)) {System.out.println("获取所有锁成功,执行转账逻辑...");}
} finally {if (multiLock != null && multiLock.isHeldByCurrentThread()) {multiLock.unlock();}
}
(4)红锁(RRedLock)
在多个独立 Redis 节点(非集群,避免集群脑裂)上获取锁,超过半数节点获取成功即视为锁获取成功,适用于对锁可用性要求极高的场景(如金融交易),避免单点 Redis 故障导致锁失效。使用示例:
// 1. 在3个独立Redis节点上创建锁
RLock lock1 = redissonClient.getLock("order:pay:1001"); // 节点1
RLock lock2 = redissonClient.getLock("order:pay:1001"); // 节点2(需单独配置RedissonClient)
RLock lock3 = redissonClient.getLock("order:pay:1001"); // 节点3// 2. 创建红锁(超过半数节点成功即生效)
RRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);try {if (redLock.tryLock(3, 5, TimeUnit.SECONDS)) {System.out.println("红锁获取成功,执行支付逻辑...");}
} finally {if (redLock != null && redLock.isHeldByCurrentThread()) {redLock.unlock();}
}
Redisson 示例
请参考项目地址中 springboot-lock/springboot-distributed-lock 模块代码。
Redisson 注意
1. 锁 Key 设计:保证唯一性
锁 Key 需与业务场景强绑定,避免不同业务共用一个 Key 导致锁冲突。例如:
- 订单创建:
order:create:{userId}
(按用户区分,避免同一用户并发创建订单); - 库存扣减:
stock:deduct:{productId}
(按商品区分,避免不同商品库存锁冲突)。
2. 安全释放锁:避免释放他人锁
- 必须在
finally
中释放锁,确保业务异常时锁仍能释放; - 释放前通过
isHeldByCurrentThread()
判断当前线程是否持有锁,避免释放其他线程的锁(如线程 A 超时未释放,锁被自动过期,线程 B 获取锁后,线程 A 恢复执行释放了线程 B 的锁)。
3. 锁粒度:尽量减小锁范围
避免将整个业务流程加锁,仅对 “共享资源修改” 的核心逻辑加锁,减少锁持有时间,提高并发效率。
4. Redis 高可用:避免锁服务单点故障
分布式锁依赖 Redis,需确保 Redis 高可用:
- 开发环境:单机 Redis(带持久化,避免重启丢失锁);
- 生产环境:Redis 集群(3 主 3 从)或哨兵模式,避免单点 Redis 宕机导致锁不可用。
5. 序列化配置:避免特殊字符问题
Redisson 默认使用 JDK 序列化,可能导致 Redis 中存储的 Key/Value 包含特殊字符(如 \xAC\xED
),建议改为 Jackson 序列化,提高可读性。
Redisson 对比
特性 | 原生 Redis 锁(setNx+expire) | Redisson 分布式锁 |
---|---|---|
重入性 | 不支持(需手动维护线程标识和重入次数) | 原生支持(RLock) |
自动续期 | 不支持(需手动定时任务续期) | 支持(Watch Dog 机制) |
锁释放安全 | 可能释放他人锁(需手动判断线程标识) | 自动判断当前线程,安全释放 |
锁类型 | 仅基础互斥锁 | 支持公平锁、读写锁、联锁、红锁等 |
易用性 | 需手动封装(原子操作、异常处理) | 开箱即用,API 简洁 |
显然,Redisson 解决了原生 Redis 锁的所有痛点,是 Spring Boot 3 分布式系统中实现分布式锁的最优选择。
总结
在生产环境中,只需关注 “锁 Key 设计”“锁粒度控制”“Redis 高可用” 三个核心点,即可安全、高效地使用 Redisson 分布式锁解决并发问题。Redisson 为 Spring Boot 3 提供了 “开箱即用” 的分布式锁解决方案,核心优势包括:
- 支持多种锁类型(可重入锁、公平锁、读写锁等),满足不同业务场景;
- 内置 Watch Dog 自动续期,避免业务未完成锁过期;
- 封装原子操作和异常处理,简化开发;
- 支持 Redis 所有部署模式,保证高可用。