Redis 分布式锁:从 SETNX 到 Redisson 的坑
470 字
2 分钟
Redis 分布式锁:从 SETNX 到 Redisson 的坑

分布式锁看上去只是「加锁、解锁」两步,实际上一个坑接一个坑。
第一版:SETNX
Boolean ok = redis.opsForValue().setIfAbsent("lock:order:1001", "1");if (Boolean.TRUE.equals(ok)) { try { // 业务逻辑 } finally { redis.delete("lock:order:1001"); }}问题:如果进程在持有锁时崩溃,锁永远不会被释放。
第二版:加上过期时间
必须把「加锁」和「设置过期」做成一个原子操作:
Boolean ok = redis.opsForValue() .setIfAbsent("lock:order:1001", token, Duration.ofSeconds(30));不要先 SETNX 再 EXPIRE,两步之间崩溃就又回到了死锁。
第三版:防止误删
假如业务执行超过 30 秒,锁已经过期并被别人拿走,此时你的 delete 会把别人的锁删掉。
做法:加锁时写入唯一标识(token),解锁时先比较再删除,并且这两步要用 Lua 脚本保证原子性:
if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1])else return 0end第四版:续期
业务耗时不确定时,固定的过期时间要么太短要么太长。解决方案是「看门狗」:持有锁期间,后台线程定时延长过期时间。
自己实现很容易出错,推荐直接使用 Redisson:
RLock lock = redissonClient.getLock("lock:order:1001");lock.lock(); // 默认开启看门狗,自动续期try { // 业务逻辑} finally { lock.unlock();}还要考虑什么
- 主从切换:主节点宕机、锁尚未同步到从节点时,可能出现两个客户端同时持锁。对一致性要求极高的场景,不要只依赖 Redis,考虑数据库唯一约束或 ZooKeeper 等方案。
- 业务幂等:锁只是减少并发冲突,不应该是唯一的正确性保证。关键操作务必做幂等设计。
- 锁粒度:锁越细越好,避免把整个服务串行化。
小结
分布式锁是工具,不是保险箱。理解它的边界,再配合幂等与兜底,才能写出真正可靠的系统。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
Redis 分布式锁:从 SETNX 到 Redisson 的坑
https://www.s9mc.cn/posts/redis-distributed-lock/相关文章智能推荐
1
Java 虚拟线程实战:用同步写法扛住十万并发
Java虚拟线程让「一请求一线程」重新变得可行。本文从原理、用法到踩坑,讲清楚它在后端服务里该怎么用。
2
MySQL 索引与执行计划:从 EXPLAIN 看懂慢查询
Java学会读 EXPLAIN,理解最左前缀、覆盖索引与索引失效场景,让慢查询无处遁形。
3
Spring Boot 优雅停机:发布时不再丢请求
Java讲清楚 Spring Boot 的优雅停机机制,以及在 Kubernetes 与负载均衡下如何配合,做到发布零报错。
4
开了十二年服,我总结的 Paper 服务器调优清单
Minecraft从 JVM 参数到区块加载,从实体清理到定时任务,一份来自十二年运维经验的 Minecraft 服务器调优清单。
5
和 AI 结对编程:我的日常工作流
AI不是让 AI 替你写代码,而是让它成为你的搭档。分享我在日常开发中使用 AI 工具的几条原则与技巧。
随机文章随机推荐









