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 {
@Autowired
private 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 分布式系统中实现分布式锁的最优选择。
Redisson 总结
在生产环境中,只需关注 “锁 Key 设计”“锁粒度控制”“Redis 高可用” 三个核心点,即可安全、高效地使用 Redisson 分布式锁解决并发问题。Redisson 为 Spring Boot 3 提供了 “开箱即用” 的分布式锁解决方案,核心优势包括:
- 支持多种锁类型(可重入锁、公平锁、读写锁等),满足不同业务场景;
- 内置 Watch Dog 自动续期,避免业务未完成锁过期;
- 封装原子操作和异常处理,简化开发;
- 支持 Redis 所有部署模式,保证高可用。

3392

被折叠的 条评论
为什么被折叠?



