分布式系统里,多个进程抢同一资源,单机锁(synchronized)失灵。怎么保证"同一时刻只有一个能改"?
一、为什么需要
订单服务部署多台机器,都用 synchronized 只锁住自己 JVM,别的机器照样改——超卖就这么来的。需要一把跨进程的锁。
二、方案 1:数据库唯一索引
建一张锁表,对某资源唯一键 INSERT,成功即拿到锁,释放就 DELETE。
-
优点:简单。缺点:无超时易死锁、性能差、DB 压力大。
三、方案 2:Redis(最常用)
SET lock_key uuid NX EX 30:不存在才设(NX),带 30 秒过期(EX),值用 uuid 防止误删别人的锁。
释放锁要用 Lua 脚本保证"判断是自己 + 删除"原子。
-
坑:1) 锁提前过期,业务没跑完 → 用看门狗自动续期(Redisson 已做);2) 主从切换丢锁 → RedLock 有争议,慎用。
四、方案 3:ZooKeeper
创建临时有序节点,最小序号的持锁;释放断开会话节点自动删,天然防死锁。
-
优点:可靠、自动释放。缺点:性能不如 Redis,依赖 ZK 集群。
五、怎么选
-
要求高可用、能容忍极小概率丢锁 → Redis(主流) -
要求强一致、不容出错 → ZooKeeper -
简单低频 → 数据库
六、面试速记
-
分布式锁解决多进程抢资源,单机锁失效。 -
Redis 用 SET NX EX + uuid + Lua 释放。 -
过期问题靠看门狗续期;主从切换可能丢锁。 -
ZK 临时节点天然防死锁,但性能低。 -
别用 del直接释放,会误删别人的锁。
七、一句话带走
Redis 一把锁:SET NX EX 加锁、uuid+Lua 释放、看门狗续期;要强一致上 ZK。别手写 del 释放锁。
系统设计面试
更多 Java 面试速通,关注公众号持续更新。
公众号聊天框回复关键字0930获取Java面试速通20篇合集!

