掌握 synchronized 代码块的关键是理解锁对象与临界区关系:只对共享且需互斥的最小代码段加锁,锁对象须为确定引用(如 this、类.class 或私有 final 对象),避免字符串或公共类对象;同步块提供可见性与可重入性,且异常时自动释放锁。

掌握 synchronized 在代码块层面的应用,关键不是背语法,而是理解“锁对象”和“临界区”的关系——只对真正共享、需互斥访问的那几行代码加锁,其余部分保持并发。
明确锁对象是谁
同步代码块的格式是 synchronized(锁对象) { ... },括号里必须是一个确定的对象引用。这个对象就是“监视器”,多个线程只有竞争同一把锁(即同一个对象实例),才会被阻塞排队。
- 用
this:适用于保护当前对象的成员变量,多个线程操作同一个实例时有效 - 用
MyClass.class:适用于保护静态资源,所有实例共用一把类锁 - 用私有 final 对象(如
private final Object lock = new Object();):最推荐,避免外部干扰,锁粒度可控 - 避免用字符串字面量或公共对象(如
String.class或Integer.class)作锁,容易引发意外的锁竞争
只包裹真正需要同步的代码
同步代码块的价值在于“细粒度”。不要把整个方法逻辑包进去,而应聚焦在读-改-写共享变量的最小原子段。
- 例如:共享计数器
count++是非原子操作(读值→+1→写回),这三步必须被同一把锁包裹 - 如果中间夹着耗时操作(如日志打印、网络调用、循环计算),应把它移出同步块,否则会严重拖慢其他线程
- 常见错误:在同步块内调用外部可能也加锁的方法(如
list.add()),易导致死锁或性能瓶颈
注意可见性与重入性
进入同步块时,JVM 会强制从主内存读取共享变量最新值;退出时,会把修改刷回主内存——这是 synchronized 提供的天然可见性保障,无需额外 volatile。
- 可重入:同一个线程可以多次进入自己已持有的锁,比如在同步块内又调用另一个用相同锁对象的同步方法,不会卡死
- 但要注意:不同锁对象之间不互通。用
this锁和用lock锁是两把独立的锁,不能互相阻塞
配合异常安全释放
JVM 保证 synchronized 块无论是否抛异常,都会执行锁释放(类似隐式 finally)。这一点比手动 Lock 更省心,但也意味着你无法在异常后做定制化清理。
- 不需要、也不应该在同步块里手动 try-catch 后再释放锁
- 若需更灵活的锁控制(如超时获取、中断响应),才考虑
java.util.concurrent.locks.ReentrantLock

















