直接回答:synchronized 修饰代码块时编译为 monitorenter/monitorexit 字节码指令,修饰方法时通过方法表的 ACC_SYNCHRONIZED 标志实现;底层每个对象关联一个 Monitor(监视器),加锁即争夺该 Monitor 的所有权。锁状态记录在对象头的 Mark Word 中。
展开解析:为降低开销,JDK 6 引入锁升级机制,只能升级不能降级(大体成立):
- 无锁:刚创建的对象;
- 偏向锁:Mark Word 记录线程 ID,同一线程重入无需 CAS,几乎没有同步开销;一旦出现其他线程竞争,需到达安全点撤销偏向;
- 轻量级锁:线程在栈帧中建 Lock Record,用 CAS 把 Mark Word 指向它,失败者自旋等待;
- 重量级锁:自旋超过阈值后膨胀,基于操作系统互斥量,未获锁线程阻塞挂起,存在用户态/内核态切换。
此外 JIT 还有锁消除(逃逸分析证明无竞争时去掉锁)和锁粗化(合并相邻细粒度锁)等优化。
易错点:偏向锁在 JDK 15 起默认禁用、后续版本逐步废弃,不要把它当作永远生效的机制;轻量级锁的自旋是适应性的。追问:Mark Word 的结构、monitor 中 owner/EntryList/WaitSet 的作用。