Java 面试宝典:synchronized的锁升级过程是怎样的?

大家好,我是大明哥,专注于「死磕 Java」系列创作的硬核程序员。本文收录于我的技术网站:https://www.skjava.com,在这里你可以找到全网最优质的系列文章、Java 全栈技术文档以及大厂完整面经。在 JDK 1.6 之前,synchronized 是一个效率较低的重量级锁。然而,为了提高锁的获取与释放效率,JDK 1.6...
Java 面试宝典:synchronized的锁升级过程是怎样的?
大家好,我是大明哥,专注于「死磕 Java」系列创作的硬核程序员。本文收录于我的技术网站:https://www.skjava.com,在这里你可以找到全网最优质的系列文章、Java 全栈技术文档以及大厂完整面经。
在 JDK 1.6 之前,synchronized 是一个效率较低的重量级锁。然而,为了提高锁的获取与释放效率,JDK 1.6 引入了偏向锁和轻量级锁,至此,锁的状态从无锁到偏向锁、轻量级锁,再到重量级锁,形成了一个由低到高的锁升级过程。
锁升级的过程是从无锁开始,逐渐过渡到偏向锁、轻量级锁,直至重量级锁。值得注意的是,锁只能升级,不能降级。锁升级的过程涉及对象头中的 Mark Word 区域,主要记录了 synchronized 相关的信息。
对象头分为对象头、实例数据和对齐填充三部分。synchronized 锁相关的信息存储在 Mark Word 区域。接下来,让我们深入了解锁的分类及其原理。
无锁表示单线程轻松愉快地运行,没有其他线程进行竞争。虽然无锁不代表没有同步机制,但它表示锁对象当前未被任何线程显式锁定。
偏向锁是 JDK 1.6 引入的锁优化机制,旨在减少锁的获取和释放的开销。当一个线程访问同步代码块并获取锁时,锁对象进入偏向模式,锁标志设置为偏向(01),且锁的拥有者被设置为当前线程。当该线程执行完同步代码块后,不会主动释放偏向锁。如果线程再次进入同步代码块,会首先检查锁是否由同一线程持有,如果是,则直接执行,避免锁的获取操作。
偏向锁的锁释放是一个被动过程,线程不会主动释放偏向锁。只有当其他线程尝试竞争偏向锁时,JVM 才会检测到锁的状态并触发撤销。撤销过程需要等待全局安全点,JVM 在全局安全点时判断锁对象是否处于未锁定状态,如果未被锁定且持有锁的线程不处于活动状态,则将对象头设置为无锁状态,撤销偏向锁。
轻量级锁在偏向锁的基础上,当一个线程持有偏向锁时,另一个线程来竞争锁时,偏向锁升级为轻量级锁。轻量级锁通过自旋的方式来竞争锁资源,减少线程阻塞和唤醒操作,提高性能。轻量级锁允许短时间的忙等(busy-waiting),用以换取线程在用户态和内核态之间切换的开销。
轻量级锁的触发条件有两个,当自旋次数超过预设阈值(默认为 10 次,可自动调整)后,锁升级为重量级锁。重量级锁依赖于对象内部的监视器(monitor),而 monitor 依赖于操作系统的 MutexLock(互斥锁)。重量级锁下,等待锁资源的线程都会被阻塞,虽然不会消耗 CPU,但阻塞或唤醒线程需要通过底层操作系统实现,涉及上下文切换和用户态与内核态之间的转换,开销较高。
锁升级的过程由无锁、偏向锁、轻量级锁到重量级锁组成。偏向锁标识为 0,锁标识为 01。当当前线程再次获取锁对象时,仅需比较偏向锁线程 ID 即可。
最后,让我们通过流程图来直观了解锁升级的详细过程(图片来源于网络)。
2024-08-20
mengvlog 阅读 7 次 更新于 2025-07-18 22:08:13 我来答关注问题0
檬味博客在线解答立即免费咨询

Java相关话题

Copyright © 2023 WWW.MENGVLOG.COM - 檬味博客
返回顶部