本文目录导读:

- Redisson 分布式锁的核心优势
- Maven 依赖
- 基本使用流程
- 核心 API 详解
- 可重入锁特性
- 公平锁(Fair Lock)
- 读写锁(ReadWriteLock)
- 红锁(RedLock)
- 异步/响应式 API
- 完整示例:秒杀场景
- 十一、常见问题与注意事项
Redisson 是一个基于 Redis 的 Java 分布式数据锁解决方案,它提供了丰富且易用的分布式锁 API,下面从核心概念、常用 API 到高级特性为你详细讲解。
Redisson 分布式锁的核心优势
相比手动实现 Redis SETNX 或使用 Jedis/Lettuce 原生客户端,Redisson 提供了:
- 自动续期:WatchDog 机制防止锁过期导致业务未完成
- 可重入:同一个线程可多次获取同一把锁
- 公平锁:按请求顺序获取锁
- 读写锁:读读不互斥,读写/写写互斥
- 红锁(RedLock):跨多个 Redis 实例的高可用锁
- 异步/响应式 API:支持 Reactive/RxJava
Maven 依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.27.2</version> <!-- 更新到最新稳定版 -->
</dependency>
基本使用流程
创建 Redisson 客户端
// 单节点模式
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379")
.setPassword("yourPassword"); // 如果设置了密码
RedissonClient redisson = Redisson.create(config);
其他模式(哨兵、集群、主从)配置方式类似。
获取锁并操作
// 获取锁对象(参数为锁的 key 名称)
RLock lock = redisson.getLock("myLock");
try {
// 1. 最常见:阻塞等待获取锁,默认锁持有时间 30 秒
lock.lock();
// 2. 也可手动指定持有时间(单位:秒)
// lock.lock(10, TimeUnit.SECONDS);
// 3. 尝试获取锁,等待 3 秒,持有 10 秒
// boolean acquired = lock.tryLock(3, 10, TimeUnit.SECONDS);
// if (!acquired) {
// throw new RuntimeException("获取锁失败");
// }
// 执行业务逻辑
doBusiness();
} finally {
// 务必要释放锁
lock.unlock();
}
核心 API 详解
lock() / lock(leaseTime, timeUnit)
| 方法 | 说明 |
|---|---|
lock() |
阻塞等待直到获取锁,默认 leaseTime = 30 秒,WatchDog 自动续期 |
lock(leaseTime, timeUnit) |
指定锁的持有时间,到期自动释放(无 WatchDog) |
WatchDog 机制:
- 当使用无参
lock()时,Redisson 启动后台线程 - 每 10 秒检查一次锁,如果业务还在执行(线程存活),则重置锁过期时间为 30 秒
- 有效防止业务时间 > 锁过期时间导致的误释放
tryLock(waitTime, leaseTime, timeUnit)
boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;
- waitTime:等待获取锁的最长时间
- leaseTime:锁的持有时间(-1 表示使用 WatchDog 自动续期)
返回 true 表示获取成功,false 表示超时未获取到。
unlock()
释放锁。必须在 finally 块中调用,否则会造成死锁。
判断锁状态
boolean isLocked = lock.isLocked(); // 锁是否被任何线程持有 boolean heldByCurrentThread = lock.isHeldByCurrentThread(); // 是否被当前线程持有 long holdCount = lock.getHoldCount(); // 当前线程持有该锁的次数(用于可重入锁)
可重入锁特性
Redisson 的 RLock 默认就是可重入的:
RLock lock = redisson.getLock("myLock");
lock.lock();
// 重入获取
lock.lock();
lock.lock();
// 需要释放相同次数
lock.unlock();
lock.unlock();
lock.unlock();
公平锁(Fair Lock)
保证锁的获取顺序与请求顺序一致(FIFO):
// 注意方法名是 getFairLock,不是 getLock
RLock fairLock = redisson.getFairLock("fairLock");
// 使用方式与普通锁完全一致
fairLock.lock();
try {
// 业务逻辑
} finally {
fairLock.unlock();
}
读写锁(ReadWriteLock)
读读不互斥,读写/写写互斥:
RReadWriteLock rwLock = redisson.getReadWriteLock("myRWLock");
RLock readLock = rwLock.readLock();
RLock writeLock = rwLock.writeLock();
// 读锁 - 多个线程可以同时持有
readLock.lock();
try {
// 读取共享数据
} finally {
readLock.unlock();
}
// 写锁 - 需要等待所有读锁和写锁释放
writeLock.lock();
try {
// 写入共享数据
} finally {
writeLock.unlock();
}
红锁(RedLock)
用于多 Redis 主节点的高可用场景:
// 需要配置多个独立的 Redis 主节点
Config config1 = new Config();
config1.useSingleServer().setAddress("redis://redis1:6379");
Config config2 = new Config();
config2.useSingleServer().setAddress("redis://redis2:6379");
Config config3 = new Config();
config3.useSingleServer().setAddress("redis://redis3:6379");
// 创建红锁
RedissonRedLock redLock = new RedissonRedLock(
Redisson.create(config1).getLock("lock1"),
Redisson.create(config2).getLock("lock2"),
Redisson.create(config3).getLock("lock3")
);
redLock.lock();
try {
// 业务逻辑(超过半数节点加锁成功才算成功)
} finally {
redLock.unlock();
}
异步/响应式 API
Redisson 支持异步无阻塞调用:
// 异步锁
RLockAsync lockAsync = redisson.getLock("asyncLock");
RFuture<Void> future = lockAsync.lockAsync();
future.whenComplete((res, ex) -> {
if (ex == null) {
// 获取锁成功
lockAsync.unlockAsync();
}
});
// 响应式锁(需要引入 spring-boot-starter-webflux 等)
RReactiveLock reactiveLock = redisson.getReactiveLock("reactiveLock");
Mono<Void> lockMono = reactiveLock.lock();
完整示例:秒杀场景
@Service
public class SeckillService {
@Autowired
private RedissonClient redisson;
public boolean seckill(Long userId, Long productId) {
String lockKey = "seckill:lock:" + productId;
RLock lock = redisson.getLock(lockKey);
try {
// 最多等待 2 秒,拿到锁后持有 5 秒(WatchDog 自动续期)
if (lock.tryLock(2, -1, TimeUnit.SECONDS)) {
// 查询库存
int stock = queryStock(productId);
if (stock > 0) {
// 扣减库存
reduceStock(productId);
// 创建订单
createOrder(userId, productId);
return true;
} else {
return false;
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("获取锁被中断", e);
} finally {
// 如果当前线程持有锁才释放
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
return false;
}
}
十一、常见问题与注意事项
WatchDog 何时启动?
- 调用
lock()无参时启动 - 调用
lock(leaseTime, unit)且leaseTime = -1时启动 - 调用
tryLock(waitTime, leaseTime, unit)且leaseTime = -1时启动
锁超时 vs 业务超时
如果业务执行时间超出预期:
- 使用 WatchDog:自动续期,无需担心
- 自定义 leaseTime:到期自动释放,即使业务未完成
建议:不确定业务耗时用 WatchDog;明确知道最大耗时用固定 leaseTime。
性能调优
// 通过配置调整 WatchDog 检查间隔(默认 10 秒) config.setLockWatchdogTimeout(5000); // 改为 5 秒
锁的粒度控制
- 粗粒度:一个锁保护所有数据 → 性能差
- 细粒度:每个数据一个锁(如
lock:user:123) → 性能好,但锁数量多
建议:根据热点数据设计,避免单个锁成为瓶颈。
Redisson 的分布式锁 API 设计直观,覆盖了大部分企业级场景:
| 场景 | 推荐方案 |
|---|---|
| 基本互斥 | getLock() + lock() |
| 需设置超时 | tryLock(waitTime, leaseTime, unit) |
| 防止业务超期 | 无参 lock() 利用 WatchDog |
| 按序获取 | getFairLock() |
| 读多写少 | getReadWriteLock() |
| 跨 Redis 高可用 | RedissonRedLock |
| 高并发非阻塞 | 异步/响应式 API |
掌握这些 API,你可以轻松应对大部分分布式锁需求,如果需要更高级的自定义(如多重锁、联锁),Redisson 也提供了 RedissonMultiLock 等组合 API。