什么是 synchronized?
synchronized 是 Java 语言提供的关键字,用于实现线程之间的互斥访问,保证多个线程在访问共享资源时的线程安全性。
它可以修饰方法或代码块,确保同一时刻只有一个线程能执行被 synchronized 保护的代码。
基本用法
1. 同步实例方法:
public synchronized void method() {
// 临界区代码
}
2. 同步静态方法:
public static synchronized void staticMethod() {
// 临界区代码
}
3. 同步代码块(指定锁对象):
Object lock = new Object();
synchronized (lock) {
// 临界区代码
}
底层原理
在 JVM 层面,synchronized 的实现依赖于 Monitor(监视器锁)。
每个 Java 对象都有一个与之关联的 Monitor,当线程进入 synchronized 代码块时,
会尝试获取该对象的 Monitor;若已被其他线程持有,则当前线程进入阻塞状态。
对象在内存中的结构包含 对象头(Object Header),其中的 Mark Word 字段用于存储锁状态(无锁、偏向锁、轻量级锁、重量级锁)。 JVM 会根据竞争程度动态升级锁状态,以平衡性能与开销。
锁升级过程:无锁 → 偏向锁 → 轻量级锁 → 重量级锁
性能与优化建议
- 尽量缩小同步范围,只同步必要的代码。
- 避免在同步块中执行耗时操作(如 I/O、网络请求)。
- 优先使用
java.util.concurrent包中的高级并发工具(如ReentrantLock、AtomicInteger)。 - 注意死锁风险:避免多个线程以不同顺序获取多个锁。
常见误区
- synchronized 保证原子性但不保证可见性? —— 错!它同时保证原子性和可见性(通过内存屏障)。
- String 常量池对象不适合作为锁 —— 正确!因为字符串常量可能被多个类共享,导致意外的锁竞争。
- synchronized 是可重入的 —— 正确!同一个线程可以多次获取同一把锁。