一个想休息的线程:JVM到底是怎么处理锁的?怎么不让我阻塞呢?

Java多线程及锁相关面试题 参考资料:https://blog.youkuaiyun.com/gongjdde/category_10948630.html?spm=1001.2014.3001.5482 常见概念: JMM:为了明确定义在多线程场景下,什么时候可以重排序,什么时候不能重排序,Java引入了JMM(Java Memory Model),也就是Java内存模型。 happen-before:这个模型就是一个规范,为了描述这个规范,JMM引入了happen-before。 内存屏障:为了禁止编译器重排序和cpu重排序,在编译器 阅读详情

我是一个线程,生活在JVM(Java虚拟机)中, 这一段日子过得有些无聊,整个世界似乎只有这一个人,天天忙着执行代码,想休息一下都很难。

我听说人类写的代码中有些特殊的地方,叫做临界区,比如synchronized修饰的方法或者代码块,他们非常神奇,在同一时刻JVM老大只允许一个线程进入执行。

实际上,老大设置了一把锁,抢到了这把锁就可以执行,否则只能阻塞,等待别人释放锁。

老大说,阻塞就是不用干活了,老老实实地等着就行。

竟然还有这等美事! 赶紧让我阻塞一次吧。

可是老大又说:“每次设置锁我都得和操作系统打交道,请他在内核中维护一个什么Mutex(互斥量)的东西,他还得把你们这些线程阻塞,切换,这可是一笔巨大的费用啊,所以这些锁还是少用为妙。”

我运气也不好,我不知道执行了多少代码,调用了多少函数,竟然一次也没遇到临界区!

我想也许这个程序员编程时不小心,没有考虑多线程并发的情况; 也有可能是这些程序大部分都是无状态的,多少个线程执行都没有问题。

于是我只好一直执行下去, 不知道过了多少天,我激动地发现,一个synchronized修饰的代码块终于出现了:

Account account = ...

synchronized(account){

    ...临界区的代码...

}

偏向锁

我满心期望别的线程已经进入了代码块,那我就可以阻塞、休息。

即使没有其他线程进入临界区,老大为我申请锁, 也得和操作系统协商什么互斥量,从用户态进入核心态,再从核心态返回用户态,总要花些功夫吧。

可是老大根本没有去找操作系统, 只是看了看这个account对象的所谓“对象头”,其中有个叫做Mark Word的东西,似乎是个什么数据结构, 里边有几个标识位,还有其他数据。

640?wx_fmt=png

老大随手使用CAS操作把我的线程ID记录到了这个Mark Word当中,修改了标识位,然后告诉我说: 可以了,你现在拥有这把锁了,进去执行代码吧。

640?wx_fmt=png

我惊奇地说:“老大你不和操作系统协商设置Mutex了?”

老大说:“不用了,你看现在就你一个线程进入了这个代码块,我只要记录下你的线程ID,就表示你拥有这把锁了,不用操作系统介入。”

我获得了锁,开始执行被synchronized包裹的代码块。

等到我第二次执行到这个synchronized的时候,老大只是看了一眼锁对象account的Mark Word就说:“你的线程ID还在,还持有着这个对象的锁,进入临界区执行吧。”

我连喘口气的机会都没有,只好继续执行。

老大说,这叫偏向锁,在没有别的线程竞争的时候,一直偏向我,可以让我一直执行下去。

我是多么期盼来一个新的线程来和我竞争啊!

轻量级锁

很快,机会就来了。

另外一个线程0x3704也要进入这个代码块执行,但是锁对象account 保存的是我的线程ID,他是没法进入临界区的。

我心想,我们两个至少得有一个进入阻塞状态,休息一会儿了。

但是老大还是不去操作系统协商,只是说: 我把这个偏向锁升级一下,变成一个轻量级的锁吧。

老大把锁对象account恢复成无锁状态,在我们俩的栈帧中各自分配了一个空间,叫做Lock Record, 把锁对象account的Mark Word在我们俩这里各自复制了一份,叫做Displaced Mark Word, 这名字真奇怪。

然后把我的Lock Record的地址使用CAS放到了Mark Word当中,并且把锁标志位改为00, 这其实就意味着我也已经获得了这个轻量级的锁了,可以继续进入临界区执行。

640?wx_fmt=png

0x3704没有获得锁,但还是不阻塞,老大让他自旋几次,等待一会儿。

等到我退出临界区,释放锁的时候,需要把这个Displaced markd word 使用CAS复制回去。接下来他就可以加锁了。

我们两个交替着进入临界区,执行这段代码,相安无事,很少出现真正的竞争。

即使是出现了竞争,想获得锁的线程只要自旋几次,等待一会儿,锁就可能释放了。

很明显,如果没有竞争或者轻度的竞争,轻量级锁仅仅使用CAS操作和Lock record就避免了重量级互斥锁的开销,对JVM老大来说,确实是个好主意。

重量级锁

轻量级锁运行得挺好,我还是没有机会休息,终于有这么一天,0x3704 正在持有锁,在临界区辛苦地执行代码。 我自旋了好多次,0x3704还是没释放锁。 这时候JVM老大说: 自旋次数太多了,太浪费CPU了,接下来升级为重量级锁!

这个重量级锁需要操作系统的帮忙,依赖操作系统底层的Mutex Lock。

只见老大创建了一个monitor 对象, 把这个对象的地址更新到了Mark word当中。

锁升级了!

640?wx_fmt=png

由于0x3704还在持有锁运行,而我终于进入了梦寐以求的状态:阻塞!  终于可以休息一下了!

仔细一想,老大煞费心机地设置了偏向锁和轻量级锁,就是为了避免阻塞,避免操作系统的介入, 这两种锁无非就是针对这两种情况:

偏向锁: 通常只有一个线程在临界区执行

轻量级锁: 可以有多个线程交替进入临界区,在竞争不激烈的时候,稍微自旋等待一下就能获得锁。

至于重量级锁,也是我最为期待的锁,那就是出现了激烈的竞争,只好让我们去阻塞休息了。

(完)

你看到的只是冰山一角, 更多精彩文章,请移步《2016文章精华》或者《2017文章精华》


码农翻身

用故事讲述技术

640?wx_fmt=jpeg

JVM---jstack分析Java线程CPU占用,线程死锁的解决 主要介绍了JVM---jstack分析Java线程CPU占用,线程死锁的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 立即下载

相关推荐

Mac用户必看:PD虚拟机网络初始化失败的3分钟修复指南(附详细截图)

本文针对Mac用户在Parallels Desktop(PD虚拟机)启动时遇到的“网络初始化失败”问题,提供了快速诊断与修复指南。核心原因是macOS系统更新后权限未正确授予。文章通过详细的三步修复法(关闭进程、修改配置文件、重新授权重启),帮助用户在3分钟内恢复虚拟机网络连接,并附有排查清单与预防建议。

weixin_29231027的博客 541

线程被堵塞后的处理方式

通过使用异步编程,我们可以在等待外设完成读写等操作的同时,让主线程运行其他代码。在操作系统内核中实现一个中断机制,当外设的状态发生变化时(例如读写完成),通过向CPU发送中断信号来唤醒线程。2.使用多线程: 如果我们要处理的任务可以分成多个子任务,那么就可以使用多线程来并行处理这些子任务。这样,当一个线程被一个外设阻塞时,其他线程可以继续执行。创建多个线程,让其中一个线程专门负责与外设进行交互,另外一个线程负责执行其他任务。当外设阻塞时,只会影响与外设交互的线程,而其他线程仍然可以正常运行。

最后一个bug的博客 2952

用pyqtgraph 和pyqt5绘制股票K线图

# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'QWidget_plot.ui' # # Created by: PyQt4 UI code generator 4.11.4 # # WARNING! All changes made in this file will be lost!...

qq_23114283的博客 5430

线程的阻塞问题

线程很灵活,但是也很扯淡

ligang2255的博客 1468

Nacos漏洞利用工具V3.0.5实战:从认证绕开到内存马植入的全流程指南

本文详细解析了Nacos漏洞利用工具V3.0.5在实战中的应用,从认证绕开到内存马植入的全流程。文章深入探讨了如何利用Nacos的历史漏洞,如默认口令、认证逻辑绕过、Derby SQL注入及Jraft反序列化,实现权限提升与持久化控制,并提供了防御视角与加固建议,旨在帮助安全人员理解攻击链以加强防护。

h6j7k8l9p0的博客 484

CyberChef本地搭建

CyberChef本地搭建

2301_80241182的博客 6085

线程似乎正在阻塞该进程

例如,输入一段python代码,询问它在什么情况下可能会导致阻塞,然后给出修正后的代码。with condition: # 在这个上下文中执行,会自动获取锁,并在退出时释放锁。with lock: # 在这个上下文中执行,会自动获取锁,并在退出时释放锁。1. 死锁:两个或多个线程在执行过程中相互等待对方释放资源,导致无法继续执行。3. 阻塞:线程因为某些原因无法继续运行,如等待I/O操作完成、获取锁等。2. 竞争条件:多个线程对同一资源进行读写操作,结果不正确。# 等待所有线程结束。

428

在Qt中使用EtherCAT-SOEM的初始化中,状态机卡在PreOp->Save-Op过程中,出现State=0x12, Error=0x001e错误的解决办法

1.在调试EtherCAT软件过程中,一直出现配置从站进不了Save_op状态,通过下函数检查从站状态: //使用的从站编号为1 只有1个从站 ec_slave[1].state = EC_STATE_SAFE_OP; ec_writestate(1); //设置到安全模式 ec_statecheck(1, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE * 4); printf("Slave %d State=0x%2.2x StatusCode=0x%4

zeal_for_rov的博客 6829

JVM 锁竞争与线程阻塞的深度定位与解决方案

JVM 锁竞争与线程阻塞定位与优化指南 锁竞争是 Java 高并发场景常见性能瓶颈,表现为 CPU 利用率高、响应延迟上升、吞吐量下降。核心排查方法: 线程状态分析:通过 jstack 检查 BLOCKED 状态线程,重点关注锁等待信息 工具诊断: Arthas 快速定位死锁和热点锁(thread -b) VisualVM 图形化监控线程状态 Async-Profiler 锁竞争火焰图分析 典型场景: 共享对象竞争(如 SimpleDateFormat) 静态集合锁冲突 死锁(哲学家就餐问题) 优化方案:

csdn_tom_168的博客 1200

mapbox高阶,加载倾斜摄影

本文详细介绍如何基于mapbox-gl v3.8.0版本实现倾斜摄影的加载,亲测可用。希望能帮助到您。一起学习,加油!加油!

我哎GIS博客 348

ShardingSphere 5.3 系列Spring 配置升级指南 | Spring Cloud 47

在 `5.3.0` 版本以前,`ShardingSphere-JDBC` 同时支持 `Java API`、`YAML`、`Spring Boot Starter` 和 `Spring Namespace` 等配置方式。 - 当新增或更新 API 时,需要调整多项配置文件,工作量大 - 社区需要维护多重配置文档和示例 - `Spring Bean` 生命周期管理容易受到项目其他依赖的影响,比如 `PostProcessor` 无法正常执行 - `Spring Boot Starter` 和 `Spring N

gmHappy 2万+

java 分析 线程堵塞 原因_一次线程阻塞问题的分析与解决

本文来自网易云社区作者:苏鹏最近部门的某产品周末时候测试服务器下会无故宕机,周一测试的同学来问具体原因,综合周末收到的哨兵系统的报警,简单分析了现象,应该是后台服务的原因。1.首先登录哨兵系统,查看我们部署的服务的状态此处内存、硬盘等指标都是比较正常的水平,但是CPU在某一个时间段非常高,所以初步判断是CPU异常导致了服务宕机(此处应有CPU状态异常图,但是当时没有把事故现场保存下来)2.登录服务...

weixin_31486289的博客 1559

Halcon算子知识:optical_flow_mg

光流(Optical Flow)是一种研究图像对齐的算法,一般包括两大类:稀疏光流和稠密光流。稀疏光流就是研究图像中稀疏点的光流,这些点一般是角点;稠密光流则是研究图像中所有点的偏移量。以下介绍halcon的基本光流算子optical_flow_mg的原理方法。该算子计算两个图片的光流法。 二、算子说明 optical_flow_mg(ImageT1, ImageT2 : VectorField : Algorithm, SmoothingSigma, Integration

gongdiwudu的专栏 1万+

一个想休息的线程:JVM到底是怎么处理锁的?怎么不让我阻塞呢?(转自码农翻身)

我是一个线程,生活在JVM(Java虚拟机)中, 这一段日子过得有些无聊,整个世界似乎只有这一个人,天天忙着执行代码,想休息一下都很难。我听说人类写的代码中有些特殊的地方,叫做临界区,比如synchronized修饰的方法或者代码块,他们非常神奇,在同一时刻JVM老大只允许一个线程进入执行。实际上,老大设置了一把锁,抢到了这把锁就可以执行,否则只能阻塞,等待别人释放锁。老大说,阻塞就是不用干活了,...

323

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

多线程进阶:锁优化

锁优化

Josvin 517

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

建议收藏:通俗易懂讲解偏向锁、轻量级锁和重量级锁

来源:码农翻身 | 作者:刘欣 我是一个线程,生活在JVM(Java虚拟机)中, 这一段日子过得有些无聊,整个世界似乎只有这一个人,天天忙着执行代码,想休息一下都很难。 我听说人类写的代码中有些特殊的地方,叫做临界区,比如synchronized修饰的方法或者代码块,他们非常神奇,在同一时刻JVM老大只允许一个线程进入执行。 实际上,老大设置了一把锁,抢到了这把锁就可以执行,否则只能阻塞,等待别人...

sinat_38170910的博客 673

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

JVM对Synchronized锁的优化

目录 JVM对锁的优化 偏向锁 轻量级锁 自旋锁 锁消除 synchronzied原理 对象头 Monitor synchronized字节码分析 轻量级锁 锁膨胀 自旋 偏向锁 偏向锁失效的几种情况 偏向锁批量重偏向 偏向锁批量撤销 锁消除 JVM对锁的优化 这里的锁优化主要是指 JVM 对 synchronized 的优化。 偏向锁 偏向锁的思想是偏向于让第一个获取锁对象的线程,这个线程在之后获取该锁就不再需要进行同步操作,甚至连 CAS 操作也不再需要..

一蓑烟雨任平生 541

锁的升级打怪:通俗易懂讲解偏向锁、轻量级锁和重量级锁

PART0: PART1: 首先通过一个小例子来解释一下三种锁的区别: 假如家里只有一个碗,当我自己在家时,没有人会和我争碗,这时即为偏向锁状态 当我和女朋友都在家吃饭时,如果女朋友不是很饿,则她会等我吃完再用我的碗去吃饭,这就是轻量级锁状态 当我和女朋友都很饿的时候,这时候就会去争抢这唯一的一个碗(贫穷的我)吃饭,这就是重量级锁状态 PART2: 我是一个线程,生活...

z69183787的专栏 1036

面试官:说说线程的阻塞、等待和自旋的区别?我:就这?

本文通过生动的生活案例和深入的技术解析,清晰阐述了Java线程的三种等待方式: 阻塞(Blocked):被动等待锁释放,如synchronized竞争失败,线程被挂起不消耗CPU资源 等待(Waiting):主动放弃资源(调用wait()/park()),需其他线程唤醒,同样不消耗CPU 自旋(Spinning):持续循环检测(如CAS),保持运行状态消耗CPU但响应最快 通过火锅店排队等位的比喻,形象说明了三种方式的区别:傻站排队(阻塞)、留号逛街(等待)、不停询问(自旋)。技术层面则从触发方式、CPU消

Apple_Boy的博客 872

漫画:Java 那么多锁,能锁住灭霸吗?

作者 |Isabella 责编 | 伍杏玲 上回码仔讲过几种锁,还记得不? 一脸懵的都去复习! 码妞问过:Java的一堆锁是干嘛的?能锁住体重吗? 上次答应说还要讲后一半的~ 这个图是不是比上次的好看点? 自旋? 自旋锁 如果此时拿不到锁,它不马上进入阻塞状态,而愿意等待一段时间。 如果循环一定的次数还拿不到锁,那么它才会进...

程序人生的博客 2726

java多线程:6、多线程中锁的升级原理是什么?什么是自旋锁?

文章目录多线程中锁的升级原理是什么? 多线程中锁的升级原理是什么?

weixin_42924812的博客 2634

16 线程休息室-waitset

文章目录概述wait set几点说明测试:线程从wait set被唤醒的顺序不一定是FIFO测试: 概述 当前线执行的执行的时候,遇到了wait方法,就会释放锁,进入阻塞状态,这个线程就会被放到waitset存起来, 其实这个waitset是不存在的一个数据结构,只是方便理解,有些人就提出了这么个概念 java 官方的一个描述(wait方法) This method causes the current thread (call it T) to place itself in the wait set

wyaoyao93的博客 526

03. 就该这么学并发 - 线程的阻塞

前言 上章介绍了**线程生命周期的就绪和运行**状态 这章讲下线程生命周期中最复杂的**阻塞**状态 阻塞(Blocked) 在开始之前 我们先**科普**几个概念 阻塞,挂起,睡眠 区分 阻塞 在线程执行时,所需要的资源不能立马得到,则线程被“阻塞”,直到满足条件则会继续执行 阻塞是一种“被动”的状态 挂起 线程执行时,因为“主观”需要,需要暂停执行当前的线程,此时需要“挂起”当前线程. 挂起是“主动”的动作行为,因为是“主动”的,所以“挂起”的线程需要“唤醒”才能继续执行 睡眠 线程执行时,因为“主

CTO技术的博客 389

【Java多线程】常见锁策略及synchronized

Java多线程,常见的锁策略以及synchronized的实现思路

weixin_62533201的博客 999

Java 多线程 | 线程生命周期与调度,这事比你想的复杂多了!

你启动的是线程,不是火箭,但 Java 会让你感觉像点了导弹发射按钮。” —— 来自一个被线程调度支配过的程序员“线程的生命周期你得理解,调度的行为你别迷信。Java 的线程调度不可控性你无法指定线程一定先跑、也无法阻止它突然睡觉。如果你觉得这篇文章对你有帮助,或者有任何想法、建议,欢迎在评论区留言交流!我是一个在代码世界里不断摸索的小码农,愿我们都能在成长的路上越走越远,越学越强!✍️ 作者:某个被流“治愈”过的 Java 老兵📅 日期:2025-07-02🧵 本文原创,转载请注明出处。

欢迎来到菜鸟不学编程的博客 503
上一篇: 由“面经”引发的思考
下一篇: 程序员的那些反模式
码农翻身
码农翻身 《码农翻身》作者 《码农翻身》作者
博客等级 码龄8年 3万+粉丝 1084原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值