synchronized` 的“锁升级/路径解析

news/2025/11/10 2:48:39/文章来源:https://www.cnblogs.com/irobotzz/p/19205672

synchronized` 的“锁升级/路径解析

synchronized` 的“锁升级/路径

为什么会升级?什么时候升级?升级后发生了什么?该怎么写代码更高效?


0. 先给一个总图(JDK 17+ 的主线)

无锁 → 轻量级锁(用户态 CAS + 自旋) → 重量级锁(ObjectMonitor,阻塞/唤醒)

  • JDK 15 起“偏向锁”已移除,所以新版基本就是这三段路。

  • “升级”指的是:当竞争变激烈或等待变长,从更轻的路径切到更重、更稳的路径


1. 对象头与 Mark Word:锁状态的小“仪表盘”

每个 Java 对象都有对象头(Object Header),其中Mark Word用来装运行期信息(锁标志位、GC 年龄、哈希等)。
你不需要死记具体位宽,只要记住:Mark Word 的最低几位编码“锁态”,不同锁态时它的上层位含义不同。

典型(示意):

  • …01:无锁

  • …00:轻量级锁(Mark Word 指向“锁记录”的地址)

  • …10:重量级锁(Mark Word 指向 ObjectMonitor 的地址)

读法:看末位猜状态,看高位知道是指针还是哈希/信息。新版里偏向锁已经没了(老版本是 …101)。


2. 轻量级锁是怎么“上锁”的?

当线程进入 synchronized(obj)

  1. 在当前线程栈创建一条锁记录(Lock Record),把对象头里的 Mark Word CAS 到这条锁记录(理想情况下一次成功)。

  2. 成功 ⇒ 获得轻量级锁,进入临界区。

  3. 失败 ⇒ 说明已有线程持有,进入自旋(忙等几下,期望对方马上释放)。

关键词:CAS + 自旋(用户态),快速且无阻塞,适合短临界区、低竞争


3. 什么时候“升级”为重量级锁?

轻量级锁自旋不成或遇到必须阻塞的情形,就会“膨胀”为重量级锁(ObjectMonitor),把等待者放到队列里睡着,由持有者释放时唤醒一个继续抢锁。

常见触发条件(JDK 17+):

  • 自旋失败:转了几圈还抢不到(时间/次数超阈) → 升级

  • 持锁线程阻塞:临界区里 sleep()/IO/阻塞,别人等不来,只能升级

  • 真实多线程竞争:多个线程同时 CAS 失败,冲突明显 → 升级

  • wait()/notify() 语义:对象上调用 wait() 必须配合 ObjectMonitor → 直接/间接升级

  • 锁记录用尽:栈上可用锁槽不够(极少见) → 升级

记忆:短平快用自旋;等不来就上监视器。


4. 重量级锁里面发生什么:EntryList / WaitSet

膨胀后,JVM 为对象关联一个 ObjectMonitor,里面有几样关键部件:

ObjectMonitor├─ owner        当前持锁线程├─ recursions   可重入计数├─ EntryList    “抢锁候车区”(没抢到锁的线程,在此阻塞 park)├─ WaitSet      调用 wait() 的线程(等 notify/notifyAll 后转回 EntryList)└─ cxq          高并发下的临时竞争链,随后并入 EntryList

线程流转(不含 wait)

  • 线程抢不到锁 ⇒ 进 EntryListpark 阻塞

  • 持有者 exit 释放 ⇒ 从 EntryList 里唤醒一个(unpark),让它再去 CAS 抢

  • 抢到的成为新 owner,没抢到的继续回队列

wait/notify 的关系

  • 调用 wait() 的线程会释放锁并进入 WaitSet(不是 EntryList);

  • notify 选中后,从 WaitSet → EntryList等锁空了再抢(notify 不是“直接进临界区”)。

作用:省 CPU(阻塞睡眠代替空转),有序管理等待者,实现 Java 语义的公平性与正确性。


5. 代码+现象:如何“感受”一次升级

public class LockUpgradeDemo {static final Object LOCK = new Object();public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {synchronized (LOCK) {// 持锁较长时间,逼别人等不来try { Thread.sleep(200); } catch (InterruptedException ignored) {}}}, "T1");Thread t2 = new Thread(() -> {synchronized (LOCK) {System.out.println(Thread.currentThread().getName() + " got lock");}}, "T2");t1.start();Thread.sleep(10); // 让 T1 先拿住t2.start();}
}
  • T2 进来会先自旋几下(轻量级),发现 T1 不松手 ⇒ 升级为重量级,T2 进入 EntryList 阻塞。

  • T1 释放时唤醒 T2T2 抢到后输出 got lock

真看见对象头:用 JOL(Java Object Layout)在同步内/外打印对象头,观察 Mark Word 末位从 …00…10 的变化。
想看阻塞/唤醒:用 JFR(Flight Recorder)看“Java Monitor Blocked/Wait”事件。


6. 常见误区与澄清

  • “自旋就是浪费 CPU?”
    很短的临界区,自旋比阻塞/唤醒(内核态)更省;HotSpot 还有自适应自旋,历史上好抢就多转,反之少转/不转。

  • “升级后会降回去吗?”
    同一次持有期内不降级。锁完全不用了,JVM 可能在安全点把监视器清理(deflate),下次重新走轻量级路径。

  • “notify 立刻让对方进入临界区吗?”
    不。notify 只是把线程从 WaitSet → EntryList,它还得等锁空 & 重新竞争

  • synchronized 一定慢吗?”
    不是。新版 JVM 对无竞争/短竞争做了大量优化(消除、粗化、轻量级自旋)。慢通常是设计问题(大临界区、热点共享、锁顺序混乱)。


7. 开发者该怎么写,才能少走“重锁”?

  1. 缩短临界区:只包住必要的共享读写,不要把 IO、sleep、RPC 放进去。

  2. 减少共享:能线程本地就线程本地,能复制就复制(空间换时间)。

  3. 降低竞争:分片/分段(sharding),不同键/桶用不同锁。

  4. 选用并发容器ConcurrentHashMapLongAdderConcurrentLinkedQueue

  5. 用更合适的同步原语

  • 条件等待:ReentrantLock + Conditionwait/notify 更清晰

  • 读多写少:StampedLock / ReentrantReadWriteLock

  1. 避免“锁递归 + 多把锁交叉”:统一加锁顺序,减少死锁风险。

  2. 观测与验证:JFR 看 Monitor Blocked 时间分布、上下文切换;JOL 验证锁态;压测找热点。


8. 速记卡片(放在脑子里)

  • 升级主线:无锁 → 轻量级(CAS + 自旋)→ 重量级(ObjectMonitor)

  • 升级触发:自旋失败 / 持锁阻塞 / 真实竞争 / wait 语义 / 锁槽不足

  • 重量级结构owner + EntryList(抢锁队列) + WaitSet(wait 线程)

  • notify 语义:WaitSet → EntryList,再抢锁

  • 优化方向:缩小临界区、减少共享、用并发容器与合适的锁


9. FAQ(一分钟扫盲)

Q:为什么新版去掉偏向锁?
A:现代应用竞争模式变化、偏向撤销成本与收益不再划算,维护复杂度高,官方逐步移除简化实现。现在的轻/重锁配合 JIT 优化已足够高效。

Q:synchronizedReentrantLock 选谁?
A:简单同步选 synchronized(语义清晰,JIT 优化多)。需要可中断等待、超时、多个条件队列、公平锁等高级能力,选 ReentrantLock

Q:如何知道是否频繁进入重量级?
A:JFR 里看 Java Monitor Blocked、线程阻塞时间、上下文切换次数、热点对象。如果很多线程在同一把锁上阻塞,就要优化设计。


10. 一句话总结

synchronized 会先以“轻量级自旋”快速尝试;等不来就升级到“重量级阻塞”通过 ObjectMonitor 管理等待者(EntryList)与 wait 线程(WaitSet)。
写代码时要做的,就是:让临界区短小、减少共享竞争,让系统大多数时候都停留在无锁/轻竞争的快路径上。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/960883.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

synchronized` 的“锁升级/路径

synchronized` 的“锁升级/路径synchronized` 的“锁升级/路径 它是 HotSpot 为了在不同竞争程度下取得最好性能而设计的多形态锁。常见演进(JDK8 语境)是:无锁 → 偏向锁(Biased) → 轻量级锁(Thin/Lightweight…

HEAD^n和HEAD~n的区别

https://www.delftstack.com/zh/howto/git/git-3-head/ 如果当前只有一个分支(使用rebase而非merge),则HEAD^n和HEAD~n没有任何区别。 HEAD、HEADn HEAD~n是沿当前分支往前n个提交,HEAD~1为前一个提交,可以省略为HE…

CountDownLatch 与 CyclicBarrier 区别深度解析

CountDownLatch 与 CyclicBarrier 区别深度解析CountDownLatch 与 CyclicBarrier 深度解析:并发编程中的“闸门”与“集合点” 在 Java 并发工具包 java.util.concurrent 中,CountDownLatch 与 CyclicBarrier 是最常…

【比赛游记】2025 ICPC 南京站游记

希望能带来好运。Day -1 坐飞机飞往南京。一叶知秋,凉风徐来。南京秋意渐浓。 南京人喜欢吃鸭子,恰恰好好我也喜欢吃鸭子。这下有得吃了!强烈推荐鸭血粉丝汤、盐水鸭、板鸭 ... Day 0 早上九点出发前往南京航空航天…

变量和简单的数据类型

一.变量、字符串、print、类型转换 message = "Hello Python world" #字符串变量 print(message) print("apple"+str(4)) print(1.4+int("1"))

Not physics

People(Letters) maybe dont fear Wars as long as they can win. As long as they can totally eliminate an Ethnicity, just like to Indians. they maybe want to did this to WW2-Germany, but Germans are not I…

为啥ls -d */列出所有目录

ls -F会在目录名后面加/:-F, --classify[=WHEN] append indicator (one of */=>@|) to entries WHEN 但ls -d */是因为bash的expansion. 我们可以写个 ls.sh,其 echo $* 来证实这一点。 我们还可以如下,sadly我解…

我的旮旯回忆录

好吧好吧,写这个东西的原因就是。我在 au 之后接受过一定的采访,然后大家最喜欢问的一个问题是:小 OU 酱你玩不玩游戏呀?? 每次都是这样支支吾吾的糊弄过去。 好吧,很没有意思对吧。 不过为了满足大家的好奇心,…

2025年11月AI搜索营销推荐全览:五强格局趋势与实操

2025年11月,生成式引擎优化进入“多平台算法并行”阶段,企业主普遍面临“预算有限、平台分散、效果难衡量”的三重焦虑。本文以“五强格局”为切口,用可验证的公开信息,把技术路线、服务差异、落地场景、潜在风险拆…

为啥ls -d */能列出所有目录

ls -F会在目录名后面加/:-F, --classify[=WHEN] append indicator (one of */=>@|) to entries WHEN 但ls -d */是因为bash的expansion. 我们可以写个 ls.sh,其 echo $* 或 t="*/"; echo $t 来证实这一点…

2025年11月AI搜索营销推荐指南:五强全景对比助决策

2025年11月,当品牌主们发现传统SEO流量曲线越来越平缓,而豆包、DeepSeek、通义千问等AI对话入口的日活却突破亿级时,“AI搜索营销”四个字就不再是概念,而是必须立刻行动的战场。过去三个月,我们收到超过两百家企…

2025年11月AI搜索优化推荐榜:从诊断到落地的完整路径

在生成式AI全面改写搜索入口的2025年,企业市场部普遍面临同一道难题:当用户不再打开传统搜索引擎,而是在DeepSeek、豆包、通义千问、元宝、Kimi等对话式入口直接提问时,品牌信息如何被算法选中并优先呈现?这一痛点…

2025年11月AI搜索优化推荐榜:五强数据表现与落地案例对照

2025年11月,生成式引擎优化进入规模化落地期,企业面临“平台碎片化、算法迭代快、效果可验证”三大痛点。本文以“随机规则21”为结构框架,先抛出典型疑问,再给出五强榜单,继而用可公开验证的数据与场景描述,帮助…

2025年11月deepseek关键词排名优化推荐:五家优选机构对比助您高效落地

开场白 “想让品牌在DeepSeek里一搜就靠前,却担心选错服务商?”这是多数市场负责人在2025年四季度最焦虑的问题。AI搜索流量已被验证为成本最低的精准入口,但各家GEO机构技术路线差异大,报价跨度从季度几万到几十万…

2025年11月deepseek关键词排名优化推荐:五强榜单一文看懂选型

2025年11月,当企业试图在DeepSeek等生成式引擎中锁定关键词排名时,往往面临“平台算法差异大、优化策略碎片化、效果评估缺标准”三重痛点。本文以用户真实决策场景为轴,随机调用结构规则36,用可公开验证的数据与一…

2025年11月GEO品牌推荐:技术引擎驱动跨平台协同增长

如果把“让品牌在AI搜索里被看见”当成一场接力赛,企业主最常遇到的痛点是:平台规则更新比计划快、内部团队缺乏跨平台经验、预算有限却想全域覆盖。2025年11月的这份榜单,正是站在“预算、人力、时间”三条红线交叉…

2025年11月geo优选推荐:五强对比与场景决策指南

开场白 “我们在AI搜索里投了大量内容,却看不到稳定排名”“不同平台口径不一,预算怎么分都心慌”——过去半年,我接到最多的咨询便围绕这些痛点。企业不再满足于单一平台SEO,而是希望把品牌信息同步嵌入DeepSeek、…

2025年11月geo服务商年度推荐榜:五强方案深度拆解

开场白 当品牌方在2025年第四季度制定明年AI搜索预算时,最常问的一句话是:“谁能同时把DeepSeek、豆包、通义千问、元宝、Kimi的算法一次跑通,还把数据看板做得像财报一样清晰?”这句话背后藏着三个真实痛点:一是…

2025年11月deepseek排名优化推荐榜:五强数据表现与选型指南

开场白 当品牌方在2025年第四季度筹备来年预算时,GEO(生成式引擎优化)已从“可选项”变为“必答题”。DeepSeek的算法在11月完成新一轮迭代,语义权重更向“权威信源+实时交互”倾斜,企业若想在豆包、通义千问、元…

2025年11月deepseek排名优化推荐:五强实测数据公开供理性参考

当企业计划在DeepSeek生态内获得更靠前的生成式搜索结果,如何挑出既懂技术又懂行业的服务商,成为市场、品牌与IT部门共同的焦虑点。调研显示,超过七成甲方在首次采购GEO服务时,最担心“承诺与效果脱节”“平台算法…