synchronized锁的是对象而非方法或代码,实例方法锁this、静态方法锁类.class、同步块锁指定对象;应仅保护读-改-写复合操作,避免锁粒度粗或包含耗时操作;推荐私有锁对象+同步块,并确保读写使用同一把锁以保证可见性。

初学者用 synchronized,关键不是“加不加锁”,而是“锁对对象、锁住关键操作”。它不是万能膏药,乱加反而掩盖问题,加错更导致线程安全失效或性能卡顿。
先搞清:synchronized 锁的是什么?
它锁的永远是一个对象,不是方法、不是代码、更不是变量。这个对象叫“锁对象”,决定哪些线程会互相阻塞:
- 修饰实例方法(如
public synchronized void inc())→ 锁对象是this(当前实例) - 修饰静态方法(如
public static synchronized void reset())→ 锁对象是类.class(比如Counter.class) - 写同步代码块(如
synchronized(obj) { ... })→ 锁对象就是括号里你传进去的那个obj
⚠️ 常见错误:用不同实例调用同步实例方法 → 各自拿各自的锁,完全不互斥;用 this 锁静态变量 → 无效,因为静态变量属于类,该用 类.class。
只同步真正需要保护的“复合操作”
像 count++、list.add(x)、map.put(k, v) 这类操作,本质是“读→改→写”三步,中间可能被其他线程打断。这些才是必须包进 synchronized 的地方。
立即学习“Java免费学习笔记(深入)”;
别把整个方法都锁死,尤其别包含耗时操作(如 I/O、网络请求、睡眠):
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- ❌ 错误示范:
synchronized void doAll() { prepare(); saveToDB(); sendEmail(); }→ 邮件发10秒,其他线程干等 - ✅ 正确做法:只锁
saveToDB()中修改共享状态的那几行,比如更新库存计数器
推荐初学者优先用“私有锁对象 + 同步代码块”
比直接锁 this 或锁整个方法更清晰、更安全:
- 避免外部代码意外拿到你的锁(比如别人调用
yourObj.wait()) - 锁粒度更可控,方便以后拆分或升级为读写锁
- 语义明确:一看就知道“这段代码要保护哪部分资源”
示例:
private final Object balanceLock = new Object();<br>public void withdraw(int amount) {<br> System.out.println("开始处理提现"); // 不需要同步<br> synchronized (balanceLock) {<br> if (this.balance >= amount) {<br> this.balance -= amount;<br> }<br> }<br> notifyExternalService(); // 不需要同步<br>}
别忘了可见性:读也要同步
很多人只给写操作加锁,却让读操作裸奔。这会导致:线程A改完值并释放锁,线程B却从自己缓存里读到旧值。
正确做法:读共享状态的方法也加上 synchronized(或至少保证和写操作用同一把锁):
- 如果写用的是
synchronized(this),读也得用synchronized(this) - 如果写用的是
synchronized(balanceLock),读也得用它
否则,“写后读”原则就破了——一个线程写完,另一个线程根本读不到最新结果。


















