synchronized在分布式环境下完全失效,因其仅作用于单个jvm,各实例无共享内存与统一监视器,无法实现跨进程互斥,导致超卖等问题;分布式锁需满足互斥性、防死锁、容错性三大条件。

synchronized 在分布式环境下完全不起作用,不是它“不好用”,而是设计上就只管单台机器上的线程协作。
根本原因:锁只在单个 JVM 内有效
synchronized 依赖对象头里的 Mark Word 和 JVM 自带的 monitor 机制,所有加锁、解锁操作都在当前进程内存里完成。集群中每个服务实例都是独立的 JVM,彼此不共享堆内存,也没有统一的监视器。三台机器上跑同样的 synchronized 代码,它们各自锁各自的线程,互不感知——就像三家人各自关起门来定规矩,谁也管不了别人家的事。
典型后果:超卖、重复提交、数据覆盖
库存扣减、优惠券发放、定时任务分发等场景,一旦部署多个实例,问题立刻暴露:
- 100 件库存,三个实例同时读到 “还有 100”,各自扣 1 件,结果变成 97,实际可能已卖出 300 件;
- 用户重复点击下单按钮,不同实例都判定“未处理”,生成多笔订单;
- 两个实例同时更新同一配置项,后写入的覆盖前写入的,中间变更丢失。
分布式锁必须满足的三个硬条件
要替代 synchronized 实现跨节点互斥,分布式锁不能只是“能加锁”,还得稳得住:
- 互斥性:全局任意时刻,只有一个客户端能成功持有锁;
- 防死锁:持有锁的服务宕机或异常退出,锁必须自动过期释放,不能卡死;
- 容错性:锁服务本身高可用,比如 Redis 主从切换不中断、ZooKeeper 多数派写入不单点故障。
常见替代方案对比要点
没有银弹,选型要看场景:
- 数据库行锁(SELECT ... FOR UPDATE):实现最简单,但吞吐低、易成 DB 瓶颈,适合低频、非核心逻辑;
- Redis(SETNX + Lua 原子脚本):性能好、延迟低,必须用 Lua 保证设值与过期时间一步完成,再配合看门狗续期防误删;
- ZooKeeper 临时顺序节点:基于 ZAB 协议强一致,天然支持监听和公平排队,适合金融级场景,但运维成本高、延迟略大。
Redlock 等多实例方案因时钟漂移和网络分区问题,已被 Redis 官方质疑,生产环境慎用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











