锁对象必须共享、唯一、稳定不变,推荐private final object lock = new object();避免用new object()(方法内)、this、string字面量或integer等易引发锁竞争的对象。

锁对象选不对,同步就形同虚设。关键不是“能不能锁”,而是“锁得准不准”——要让所有竞争线程争同一把锁,又不误伤无关线程。
锁对象必须是共享、唯一、稳定不变的
多个线程得能访问到同一个对象,且这个对象不能被替换、不能是临时创建的。
- ✅ 推荐:private final Object lock = new Object(); —— 专用、私有、不可变,生命周期与宿主对象一致
- ✅ 合理场景:操作某个业务实体(如
Account account),且该对象在多线程间长期复用、不被重新赋值,可用account本身作锁 - ❌ 避免:
new Object()写在方法内(每次新建,锁不同);this(若类被继承或代理,可能泄露或语义模糊);String字面量或Integer等包装类(常量池导致意外锁竞争)
按数据归属决定锁粒度
锁的范围要和你要保护的数据范围对齐,既不能太大拖慢并发,也不能太小失去保护作用。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 保护实例变量(如用户余额)→ 锁该用户对应的唯一对象,比如用
ConcurrentHashMap<long object></long>缓存每个userId的专用锁 - 保护静态计数器(如总请求次数)→ 锁
MyClass.class或专用private static final Object CLASS_LOCK = new Object(); - 保护某类资源(如商品库存)→ 锁
itemId对应的锁对象,而不是整个服务实例
避免锁对象参与业务逻辑或外部交互
锁对象应当“只管同步,不管干活”,否则容易引发死锁或状态污染。
- 不要把锁对象作为参数传给外部方法,尤其不可控的第三方调用
- 不要在
synchronized(lock)块里调用另一个也加锁的方法,除非明确设计为可重入且锁对象一致 - 锁对象不应是可变业务对象(如一个会
setXXX()的 DTO),防止锁期间被意外修改或回收
优先考虑无锁方案,再退而求锁
不是所有共享访问都需要 synchronized。先看有没有更轻量、更安全的替代方式。
- 纯计数、标志位 → 用
AtomicInteger、AtomicBoolean,天然原子+可见 - 高频读写 Map → 用
ConcurrentHashMap,分段/跳表结构已做细粒度控制 - 复合操作(查+改)无法拆解 → 再回到同步块,但务必确保临界区最小,且锁对象精准
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










