synchronized 是 java 中通过“加锁—执行—释放”保障线程安全的机制,锁对象决定作用范围:实例方法锁 this、静态方法锁 class、代码块锁指定对象;需精准锁定临界区以避免过度阻塞,并兼具互斥、可见性与有序性,且支持可重入与异常自动释放。

synchronized 是 Java 中最直接、最常用的线程安全保障手段,它通过“加锁—执行—释放”的机制,确保多个线程对共享资源的访问是互斥且可见的。关键不在于“加了锁”,而在于“锁对了对象”和“锁住了该锁的范围”。
锁的对象必须明确:this、Class 或自定义对象
锁不是凭空存在的,它一定依附于某个对象。synchronized 的行为完全取决于你锁的是谁:
- 修饰实例方法(如 public synchronized void doWork())→ 锁的是当前实例 this;不同对象实例之间互不影响
- 修饰静态方法(如 public static synchronized void init())→ 锁的是当前类的 MyClass.class 对象;所有线程共用同一把类锁
- 同步代码块(如 synchronized(lockObj) { ... })→ 锁的是你指定的任意非 null 对象;推荐用私有 final 对象,避免被外部误操作
只锁真正需要保护的临界区,别锁整个方法
把整个方法都用 synchronized 修饰,看似简单,但容易造成不必要的阻塞。比如一个方法里只有 2 行在改共享变量,其余都是日志或计算,那锁住全部就浪费了并发机会。
更合理的做法是:
- 提取出真正读写共享变量的代码段
- 用 synchronized(shareLock) { ... } 包裹它
- 让非共享操作(如 IO、本地变量运算)在锁外执行
它不只是互斥,还保证可见性和有序性
synchronized 不仅阻止多个线程同时进入,还会在锁释放时把线程本地修改的变量值刷回主内存;下个获取同一把锁的线程,一定会看到前一个线程的最新结果——这点比 volatile 更强,因为 volatile 不能保证复合操作(如 i++)的原子性。
例如:
- 线程 A 执行 synchronized(this) { count++; } 后退出 → count 新值写入主内存
- 线程 B 随后进入同一个 synchronized(this) 块 → 强制从主内存读取 count,不会看到旧缓存值
注意可重入与异常安全
Java 的 synchronized 是可重入锁:同一线程可以多次进入自己已持有的锁,不会死锁。而且它异常安全——无论代码块中是否抛出异常,锁都会自动释放,无需手动处理。
这意味着你不需要 try-finally 来保证解锁,也无需担心因未 catch 异常导致锁永久占用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











