synchronized核心作用是让多线程排队访问共享资源,解决原子性、可见性、有序性三大问题;锁对象决定同步范围,需避免死锁与滥用;JDK 1.6后已优化,性能并非瓶颈。
synchronized 的核心作用是:让多线程「排队访问共享资源」,避免数据错乱、读到脏值或执行结果不可预期。
靠 boolean isRunning 这类手动标记根本不可靠——它既不能阻止线程同时进入临界区(缺乏互斥),也无法保证修改立刻被其他线程看到(缺乏可见性)。而 synchronized 一次性解决三个问题:
这三点不是“可选功能”,是 JVM 规范强制保证的,靠手写逻辑无法等效实现。
锁对象决定了同步范围,选错就等于没锁:
synchronized(this) 锁的是当前实例对象,不同对象之间完全不干扰。适合保护实例变量(如 private int count)synch
ronized(Counter.class) 或 public static synchronized void inc() 锁的是类对象,所有该类的实例共用一把锁。适合保护静态变量或全局计数器synchronized(new Object()) —— 每次新建对象,锁对象都不同,等于没加锁public class Counter {
private int instanceCount = 0;
private static int staticCount = 0;
// ✅ 正确:保护实例变量
public void incrementInstance() {
synchronized (this) {
instanceCount++;
}
}
// ✅ 正确:保护静态变量
public static void incrementStatic() {
synchronized (Counter.class) {
staticCount++;
}
}
}
死锁不是小概率事件,而是锁顺序不一致的必然结果。典型模式:
lock1 再锁 lock2
lock2 再锁 lock1
规避方法只有两条硬规则:
lock1 后 lock2)ReentrantLock.tryLock(timeout) 带超时的尝试获取,失败就释放已持锁并重试很多人还在用“synchronized 是重量级锁”当口头禅,但现实是:
synchronized 成为瓶颈,否则别急着换 ReentrantLock;后者更灵活,但也更易出错(比如忘记 unlock())真正影响性能的,往往不是锁本身,而是同步块里干了太多事——比如在 synchronized 里调远程接口、解析大 JSON、做复杂计算。把耗时操作移出去,比换锁类型管用十倍。
最常被忽略的一点:synchronized 的锁释放是「自动且绝对可靠」的——哪怕方法抛异常、return 中断、甚至 JVM crash(在正常运行路径下),JVM 都会确保 monitorexit 执行。这点比手动管理的锁更安全,也更省心。