纯干货、无废话、直接可用,一文搞懂 redissonClient.getLock()
一、先上结论
ini
RLock lock = redissonClient.getLock("order:create:" + orderId);
这行代码的作用:获取一个 Redis 分布式锁,用来解决并发重复请求、重复提交、超卖、数据不一致等问题。如果你已经会用了,建议直接跳到"坑"的部分;如果还不太熟,往下看。
二、核心概念(背下来)
1. 锁名称规则
- 同一个 key:同一把锁
- 不同 key:不同锁
- 命名格式:业务模块:功能:唯一标识
- 命名示例 :
order:create:1001stock:deduct:SKU123lock1(无业务含义)
2. 锁的三个特性
- 互斥:同一时间只有一个线程能拿到锁
- 阻塞:拿不到锁会等待,直到锁释放
- 自动续期:Redisson 自带看门狗(WatchDog),任务没执行完会自动延长锁时间
三、标准代码模板(复制即用)
csharp
String lockKey = "order:create:" + orderId;
RLock lock = redissonClient.getLock(lockKey);
try {
// 获取锁(阻塞等待,自动续期)
lock.lock();
// ========== 需要加锁的业务逻辑 ==========
doBusiness();
} finally {
// 必须解锁!且要判断当前线程是否持有锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
这个模板就是你项目的标准答案,没有第二种写法。
四、三种加锁方式对比
1. lock() ------ 最常用、最安全
csharp
lock.lock();
- 等待方式:阻塞等待,拿不到锁一直等
- 续期机制: 自动续期(看门狗)
- 适用场景:绝大多数业务(订单创建、库存扣减、数据更新)
2. tryLock(0, time, unit) ------ 尝试一次,拿不到就放弃
csharp
boolean locked = lock.tryLock(0, 10, TimeUnit.SECONDS);
if (locked) {
try {
// 业务逻辑
} finally {
lock.unlock();
}
}
- 等待方式:不等待,立即返回
- 续期机制: 无自动续期
- 适用场景:防止重复请求、接口幂等校验
3. tryLock(waitTime, leaseTime, unit) ------ 等待一段时间
ini
boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
- 等待方式:等待 3 秒,拿不到返回 false
- 锁时长:10 秒自动释放
- 续期机制: 无自动续期
五、5条铁律(面试必问、开发必守)
规则1:必须 try-finally 包裹
-
目的:无论业务是否报错,锁一定释放
// 错误写法 lock.lock(); doBusiness(); lock.unlock(); // 如果业务抛异常,这行不执行 → 死锁
// 正确写法 try { lock.lock(); doBusiness(); } finally { lock.unlock(); }
规则2:解锁前必须判断 isHeldByCurrentThread()
-
目的:防止其他线程解锁你的锁
// 危险写法 finally { lock.unlock(); // 如果锁已经被其他线程持有,会报错 }
// 安全写法 finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } }
规则3:不要手动设置锁超时时间(除非你确定业务执行时间很短)
lock.lock(10, TimeUnit.SECONDS):业务执行超过 10 秒,锁提前释放 → 锁失效lock.lock():看门狗自动续期,最安全
规则4:锁粒度越小越好
csharp
// 锁住整个方法(粒度太大)
@Transactional
public void createOrder() {
lock.lock();
// 整个方法
}
// 只锁关键代码块
public void createOrder() {
// 前置校验...
lock.lock();
try {
// 只锁写操作
} finally {
lock.unlock();
}
}
规则5:锁名称必须有业务意义
- 订单创建:
order:create:{orderId} - 库存扣减:
stock:deduct:{skuId} - 用户签到:
user:sign:{userId}:{date}
六、终极模板(企业级标准)
csharp
@Component
public class DistributedLockService {
@Autowired
private RedissonClient redissonClient;
public <T> T executeWithLock(String lockKey, Supplier<T> supplier) {
RLock lock = redissonClient.getLock(lockKey);
try {
lock.lock();
return supplier.get();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
// 使用方式
String result = distributedLockService.executeWithLock(
"order:create:" + orderId,
() -> orderService.createOrder(orderId)
);
七、你最容易踩的5个坑
- 不在 finally 解锁:导致死锁。解决方案:用 try-finally。
- 不判断 isHeldByCurrentThread:其他线程解锁你的锁。解决方案:解锁前判断。
- 手动设置 lock 时间:业务超时导致锁提前释放。解决方案:用 lock()。
- 锁粒度太大:性能差。解决方案:只锁关键代码。
- 锁名称重复:不同业务互相阻塞。解决方案:按规范命名。
八、一句话总结
redissonClient.getLock(redisLock) = 获取分布式锁。
使用公式:lock() + try + finally + isHeldByCurrentThread 判断。把这个公式刻在脑子里,你的分布式锁就不会出问题。