航母指挥官2免安装绿色中文版
1.21G · 2025-09-11
咱们先打个比方:
单机锁就像你家的房门钥匙—— 家里就你一个人用,钥匙放兜里,想开门就开,不用怕别人抢(单 JVM 进程内,线程间竞争锁,synchronized、ReentrantLock就能搞定)。
但如果是分布式系统,比如你做了个电商平台,部署了 3 台服务器(3 个 JVM),用户下单要扣库存。这时候 3 台机器里的线程都要改 “库存” 这个共享数据,相当于 “3 户人共用一个小区大门”—— 你家的钥匙(单机锁)肯定管不了另外两家啊!
这时候就需要分布式锁:它得是一把 “小区大门卡”,3 台机器的线程都得凭这张卡开门,而且同一时间只能有一个线程拿到卡(保证互斥),还得防止 “卡丢了门一直锁着”(避免死锁)。
市面上的分布式锁方案不少,但坑也多,咱们先排排雷:
方案 | 原理 | 优点 | 缺点 |
---|---|---|---|
数据库锁 | 用for update悲观锁 / 唯一索引 | 不用额外中间件 | 性能差!高并发下数据库扛不住 |
ZooKeeper | 基于临时有序节点 | 强一致性,自动释放锁 | 部署复杂,重连机制麻烦 |
Redis 锁 | 基于键值对的原子操作 | 轻量、高性能、易部署 | 需要自己处理过期、误删问题 |
显然,Redis 是后端最常用的选择—— 但千万别以为 “用 Redis 的 set 命令就能搞定”,这里面的坑能让你调试到半夜!
很多同学一开始会这么写:先用setnx key value(只有 key 不存在时才设置成功,保证互斥),再用expire key 10(给锁加过期时间,避免死锁)。
但这是错的! 因为setnx和expire是两步操作,中间如果服务器宕机,锁就没了过期时间,直接变成 “死锁”!
正确姿势是用Redis 的原子 set 命令:
SET lock_key unique_value NX EX 10
拆解一下这几个参数的作用:
这行命令把 “加锁 + 设过期” 变成了一步原子操作,完美避免了 “加锁后宕机” 的死锁问题~ 但别急,这只是入门,还有两个大问题没解决:锁过期了怎么办?锁被别人误删了怎么办?
手写 Redis 锁的同学,迟早会遇到这两个灵魂拷问:
别慌!Redisson早就把这些问题封装好了,相当于给你一个 “现成的锁工具包”,拿来就能用,还不用自己填坑~ 咱们逐个看它是怎么解决的。
比如你给锁设了 30 秒过期,但业务逻辑要执行 1 分钟 —— 这时候锁到期会被自动释放,别的线程就会抢锁,导致 “并发安全问题”。
Redisson 的解决办法是内置 “看门狗”(Watch Dog) :
相当于小区保安(看门狗)定期巡逻,看到你还在屋里(持有锁),就自动帮你把大门卡的有效期续上,再也不怕 “锁提前过期” 了!
代码示例(Spring Boot 中使用):
// 获取Redisson客户端
RLock redissonLock = redissonClient.getLock("stock_lock");
try {
// 加锁:默认30秒过期,看门狗自动续期
redissonLock.lock();
// 执行业务:就算执行1分钟,锁也不会过期
updateStock();
} finally {
// 释放锁
redissonLock.unlock();
}
假设这么个场景:
Redisson 怎么解决?给锁加唯一标识,释放前先判断:
-- 判断锁值是不是自己的,是才删除
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
你不用自己写这段 Lua 脚本,Redisson 的unlock()方法已经帮你封装好了 —— 调用就行,省心!
手写 Redis 锁时,抢锁失败了你得自己写 while 循环重试:
// 手写重试,麻烦又不优雅
while (!redisTemplate.opsForValue().setIfAbsent("lock", "value", 10, TimeUnit.SECONDS)) {
// 重试间隔:硬编码,不好维护
Thread.sleep(100);
}
Redisson 直接帮你搞定了重试逻辑,还支持配置重试次数和间隔:
// 抢锁失败后,最多重试3次,每次间隔500毫秒
boolean isLocked = redissonLock.tryLock(3, 500, TimeUnit.MILLISECONDS);
if (isLocked) {
try {
updateStock();
} finally {
redissonLock.unlock();
}
} else {
// 重试3次还没抢到锁,返回友好提示
return "当前下单人数过多,请稍后再试~";
}
甚至你还能自定义重试策略,比如 “指数退避重试”(重试间隔越来越长),Redisson 都支持 —— 不用自己造轮子,香!
咱们回头捋一捋:
最后给大家一个小建议:项目里别再手写 Redis 分布式锁了,直接集成 Redisson—— 几行代码搞定,还能少加班!
你们在项目中用分布式锁踩过哪些坑?比如 “锁没释放导致服务卡死”“重试次数没调好导致性能差”?欢迎在评论区交流~ 觉得有用的话,点赞关注走一波,下次再跟大家扒更多后端干货!
杭州萧山推出线下消费补贴:18-40 岁青年购 3C 数码产品最高可补 1000 元
努比亚张雷:手机市场从不是“非此即彼”的零和博弈,行业活力正来自这种差异化