Java分布式锁实战:Redisson从入门到生产级应用
在分布式系统中,解决资源并发访问冲突是核心挑战之一。传统单机的synchronized或ReentrantLock无法跨JVM生效,因此分布式锁成为必备技术。Redisson作为基于Redis的Java客户端,提供了简单且强大的分布式锁实现方案。本文将手把手教你如何使用Redisson实现分布式锁,并深入分析其底层原理。
一、Redisson分布式锁核心原理
1.1 底层数据结构
- Redis Hash结构存储锁信息:
KEY: "lock:order:1001" VALUE: field: "8743c9c0-0795-4907-87fd-6c719a6b4586:1" (客户端ID+线程ID) value: 1 (重入次数)
1.2 WatchDog自动续期机制
Redisson 提供了 “看门狗” 自动续期机制,默认持锁 30 秒。只要持锁的客户端不断地续期,锁将一直有效,直到显式释放。
二、生产级代码实现
2.1 添加Maven依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.21.0</version>
</dependency>
2.2 Redis YAML配置
# application.ym
spring:
redis:
host: localhost # Redis服务器地址
port: 6379 # Redis服务器端口
password: # Redis服务器密码(如果设置了密码)
database: 0 # Redis数据库索引,默认为0
2.3 基础锁实现(含异常处理)
@Service
@Slf4j
@RequiredArgsConstructor
public class OrderService {
private final RedissonClient redisson;
private static final String LOCK_PREFIX = "lock:order:";
/**
* 创建订单(带分布式锁)
* @param orderId 订单ID
*/
public void createOrder(String orderId) {
final String lockKey = LOCK_PREFIX + orderId;
final RLock lock = redisson.getLock(lockKey);
try {
// 尝试获取锁(等待3秒,锁持有时间20秒)
if (!lock.tryLock(3, 20, TimeUnit.SECONDS)) {
log.warn("[Redisson] 获取订单锁失败,orderId: {}", orderId);
throw new BusinessException(ErrorCode.LOCK_ACQUIRE_FAILED);
}
// 获取锁成功后执行业务逻辑
log.info("[Redisson] 成功获取订单锁,开始处理订单:{}", orderId);
processOrder(orderId);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("[Redisson] 订单处理被中断,orderId: {}", orderId, e);
throw new BusinessException(ErrorCode.THREAD_INTERRUPTED);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
log.info("[Redisson] 已释放订单锁,orderId: {}", orderId);
}
}
}
private void processOrder(String orderId) {
// 模拟业务处理耗时
try {
TimeUnit.MILLISECONDS.sleep(500 + new Random().nextInt(500));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
log.info("订单处理完成:{}", orderId);
}
}
三、高级锁类型实现
3.1 公平锁实现
public void processWithFairLock(String resourceId) {
RLock fairLock = redisson.getFairLock("fairLock:" + resourceId);
try {
fairLock.lock(30, TimeUnit.SECONDS); // 公平锁获取
// 业务逻辑...
} finally {
fairLock.unlock();
}
}
3.2 联锁(MultiLock)应用
public void multiResourceOperation(String res1, String res2) {
RLock lock1 = redisson.getLock("res1:" + res1);
RLock lock2 = redisson.getLock("res2:" + res2);
RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2);
try {
if (multiLock.tryLock(5, 30, TimeUnit.SECONDS)) {
// 多个资源原子操作
}
} finally {
multiLock.unlock();
}
}
3.3 红锁(RedLock)实现
public void multiResourceOperation(String res1, String res2) {
RLock lock1 = redisson.getLock("res1:" + res1);
RLock lock2 = redisson.getLock("res2:" + res2);
RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2);
try {
if (multiLock.tryLock(5, 30, TimeUnit.SECONDS)) {
// 多个资源原子操作
}
} finally {
multiLock.unlock();
}
}
四、生产环境最佳实践
4.1 锁命名规范
// 推荐格式:lock:业务模块:资源类型:资源ID
String lockKey = "lock:order:payment:" + orderId;
4.2 异常处理策略
try {
// 尝试获取锁...
} catch (RedisTimeoutException e) {
metricsCollector.recordLockTimeout(); // 监控上报
throw new ServiceException("系统繁忙,请稍后重试");
} catch (Exception e) {
log.error("锁操作异常", e);
throw new ServiceException("系统错误");
}
五、常见问题排查指南
5.1 锁无法释放
检查点:
- 是否在finally块中调用unlock()
- 是否出现线程复用导致线程ID变化
- Redis连接是否正常
5.2 锁续期失败
检查点:
- WatchDog线程是否正常运行
- 是否显式设置了leaseTime
- Redis服务器时间是否同步
5.3 性能瓶颈
优化方向:
- 缩小锁粒度(从全局锁改为资源级锁)
- 使用读写锁分离场景
- 增加Redis分片
六、总结
通过Redisson实现分布式锁,开发者可以:
✅ 快速集成成熟的分布式锁方案
✅ 避免重复造轮子的风险
✅ 享受自动续期、可重入等高级特性
结语:
如有问题,还望告知。不胜感激!
这篇文章对你有帮助的话,动动你可爱的小手指,点个赞再走吧。非常感谢!