Redisson 是 Java 中成熟的 Redis 客户端,原生支持分布式锁(可重入、公平、联锁、红锁)和基于 ZSET+定时轮询的延迟队列,使用需正确初始化、合理选型、理解机制并妥善处理异常与资源释放。

Redisson 是 Java 中非常成熟的 Redis 客户端,它原生支持分布式锁(如可重入、公平、联锁、红锁)和延迟队列(基于 Redis 的 ZSET + 定时轮询),用法简洁且线程安全。关键在于正确初始化客户端、合理选择锁模式、理解延迟队列的触发机制,并处理好异常与资源释放。
一、引入依赖并初始化 RedissonClient
使用 Maven 引入 Redisson(推荐 3.24.0+,兼容 Redis 7+ 和 Spring Boot 3):
<dependency><groupid>org.redisson</groupid><artifactid>redisson-spring-boot-starter</artifactid><version>3.24.0</version></dependency>
配置 application.yml(单节点示例):
redisson:
single-server-config:
address: redis://127.0.0.1:6379
connection-pool-size: 64
connection-minimum-idle-size: 24
retry-attempts: 3
retry-interval: 1500
Spring Boot 会自动注入 RedissonClient Bean。若需自定义,也可通过 Config 手动构建。
二、用 Redisson 实现可靠的分布式锁
推荐使用 RLock 接口,它支持自动续期(watchdog)、可重入、阻塞等待等特性,避免死锁和误释放。
典型用法(带超时与自动续期):
- 调用
lock(key, leaseTime, timeUnit):加锁并指定持有时间,超时自动释放; - 调用
tryLock(waitTime, leaseTime, timeUnit):最多等待waitTime,成功后持有leaseTime; - 务必在
finally块中unlock(),或使用try-with-resources(配合RLock的autoUnlock封装); - 不要用字符串拼接 key,建议统一前缀(如
"order:lock:" + orderId),避免命名冲突。
示例代码:
RLOCK lock = redissonClient.getLock("order:lock:1001");
try {
if (lock.tryLock(3, 10, TimeUnit.SECONDS)) { // 等最多 3s,持有 10s
// 执行业务逻辑(如扣减库存)
processOrder();
} else {
throw new RuntimeException("获取锁失败");
}
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
三、用 RDelayedQueue 实现延迟队列
Redisson 的延迟队列本质是「延迟任务注册 + 后台定时扫描」:任务先存入 ZSET(score 为执行时间戳),Redisson 内部线程定期拉取到期任务,投递到关联的 RBlockingQueue 中供消费者处理。
关键步骤:
- 创建一个普通队列(如
RBlockingQueue); - 通过
getDelayedQueue()获取其延迟代理对象; - 调用
offer(task, delay, timeUnit)投递延迟任务(底层自动设置 ZSET score); - 另起线程或用 Spring @EventListener 监听队列,调用
poll()或take()消费。
注意点:
- 延迟精度取决于 Redisson 的扫描间隔(默认 5 秒,可通过
Config.setDelayQueueScanInterval()调整); - 任务对象必须可序列化(实现
Serializable); - 不支持跨 JVM 的延迟任务取消(除非手动
remove()),适合中小规模延迟场景(如订单超时关单、短信补发)。
示例:
RBlockingQueue<string> queue = redissonClient.getBlockingQueue("delayed:queue");
RDelayedQueue<string> delayedQueue = queue.getDelayedQueue();
// 5 秒后执行
delayedQueue.offer("order_1001_timeout", 5, TimeUnit.SECONDS);
// 消费端(建议单独线程)
new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
String task = queue.poll(); // 或 take()
if (task != null) handleTimeout(task);
} catch (Exception e) {
Thread.sleep(100);
}
}
}).start();</string></string>
四、生产注意事项
实际项目中容易忽略但影响稳定性的问题:
- 锁粒度要细:按业务维度(如用户 ID、订单 ID)分锁,避免大锁串行化;
- 延迟队列不保证严格准时:受扫描间隔、网络、JVM GC 影响,仅适用于“大致延迟”场景;
-
避免锁重入陷阱:同一个线程多次
lock()是允许的,但unlock()次数必须匹配,否则锁不会真正释放; -
连接池与超时配置要合理:高并发下连接不足会导致锁获取失败,建议监控
redisson_connection_pool_used等指标; - Spring 环境下慎用 @Transactional + 分布式锁:锁范围应包裹整个事务逻辑,否则可能因事务未提交导致其他节点读到旧数据。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











