synchronized 底层实现原理、重量级锁、轻量锁、锁膨胀、锁自旋、偏向锁详解

news2024/11/25 14:25:48

目录

0、基础知识:Java对象的存储格式

1. synchronized底层:Monitor(重量级锁):被锁的对象与Monitor的关系 

2. synchronized底层:轻量级锁优化,栈帧与被锁的对象的关系

3. 锁膨胀(轻量级锁升级为重量级锁)

4. 自旋优化---对“重量级锁”的优化

5. 偏向锁----对“轻量级锁”的优化

        5.1 偏向锁的核心思想 

        5.2 偏向状态

        5.3 偏向撤销   

        5.4  批量重偏向 与 批量撤销


0、基础知识:Java对象的存储格式

        在JVM中,对象拥有一个“对象头”,格式如下,其中包括了标记字(Mark Word)和类型指针(Class Pointer),Klass Word指向的是该对象所属的类,而Mark Word中记录了对象的一些状态信息,包括对象的哈希码、锁状态和GC相关信息等。

1、 synchronized底层:Monitor(重量级锁):被锁的对象与Monitor的关系 

         每个Java对象可以关联一个Monitor对象,其内部有如下图中的这些属性,Owner用来标记 这个Monitor的所有者是谁。
(1)当有线程(称为Thread-2)运行如下程序时,即在给对象obj上锁,此时,该对象头的Mark Word,就会被设置成一个指向Monitor对象的指针。

synchronized(obj){
    ....
}

         此时,Thread-2会变为Monitor的Owner。

(2)当此时,有别的线程(Thread-1)运行到代码块时,会检查这个obj有没有关联Monitior(有无指向?),发现已经关联了(看MarkWord里的01、00、10)、并且Owner已经有主人了,此时将Thread-1放入EntryList阻塞队列,并且该线程进入Blocked状态。若还有别的线程,则同上。

 (3)当Thread-2代码块运行结束后,断开与Monitor的连接,此时会通知MonitorEntryList,将这些线程唤醒,(此时是不公平竞争),可能Thread-1就成为了Monitor新的主人,其余线程仍然Blocked

2、 synchronized底层:轻量级锁优化,栈帧与被锁的对象的关系

        轻量级锁:如果一个对象虽然是多线程访问,但多线程访问的时间是错开的(没有竞争),则可以用轻量级锁来优化,此时不需要Monitor

static final Object obj = new Object();
public static void method1(){
    synchronized(obj){
    //同步块A
    method2();
}
public static void method2(){
    synchronized(obj){
    //同步块B
    ...
}

        当线程调用方法,会创建一个栈帧,栈帧里包含一个锁记录的结构:
        主要内容有:(1)锁记录的地址(2)对象指针
步骤1:
        当执行到加锁的时候:做如下处理,并尝试将LockRecord的地址与 Object的MarkWord做交换!

         如果标记位为01(Normal)状态,则可以交换(反之如果不是01,则有两种可能:
                1.如果有其他锁获得这个对象了,则 将会进行“锁膨胀”;
                2.
如果是自己又一次获得锁(锁重入),添加一条锁记录),
        交换后,对象头中的状态便由01变为00。

          步骤2:当执行完相应线程的代码,则释放锁记录的内存:

 3、锁膨胀(轻量级锁升级为重量级锁)

        承接上文,如果发生如下情况时,则会进入锁膨胀过程

过程:    

  •  轻->重:申请Monitor锁,Object的MarkWord不再指向锁记录,而指向Monitor对象(如第1节所讲的那样),并且最后两位会变成10(重量级锁状态)
  •  Thread-1这个被阻塞的线程,自己进入EntryList,进入Blocked状态(如第1节所讲的那样)
  •  该Monitor的Owner是Thread-0

解锁: 步骤同前文的第1节

4.    自旋优化---对“重量级锁”的优化

        线程的阻塞与运行将带来上下文的切换,耗费资源。自旋优化能够缓解阻塞:
        概括:在获取monitor时如果失败了,不立刻进入EntryList阻塞,而是自旋重试几次(如果试了几次都还是失败,再去阻塞)

5. 偏向锁----对“轻量级锁”的优化

5.1 偏向锁的核心思想 

        在上文中可知,轻量级锁在没有竞争时(还是这个线程来获取锁),将会发生锁重入,要执行CAS操作,并在栈桢创建新的锁记录。这样耗费了资源。
        优化方式:只有第一次使用CAS将线程ID设置到被锁对象的MarkWord中,以后再来的线程只用验证这个线程ID是自己则没有竞争,无需CAS。
        以后只要不发生竞争,这个对象归线程所有。

5.2 偏向状态

        biased_lock的0、1表示着:不是or是 偏向锁

5.3 偏向撤销   

  1. 当有其他线程尝试获取同一个对象的锁时,偏向锁会被撤销。

  2. 当一个线程访问同步块时,如果检测到该对象处于偏向状态,并且线程 ID 不匹配,也会触发偏向锁撤销

  3. 调用wait/notify:只有重量级锁才有这样的机制

5.4  批量重偏向 与 批量撤销

        如果被锁的对象虽然被多个线程访问,但没有发生竞争(例如,先让偏向锁的线程全都执行完了,再让别的一些线程来获取这个锁),这时偏向锁的偏向可能发生改变:
        当撤销偏向锁阈值超过20次,jvm会认为自己偏向错了,于是回重新偏向。

        当撤销偏向锁的次数超过40次,jvm会认为不该偏向,则整个类所有对象会变为不可偏向(即MarkWord最后三位变为001

  

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

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

相关文章

【arduino】HC-SR04超声波测距模块的驱动与使用

arduino超声波测距模块的驱动与使用 什么是超声波测距模块参数:引脚定义电路超声波传感器的控制时序驱动代码接线代码工程文件超声波是振动频率高于20KHZ的机械波。它具有频率高、波长短、绕射现象小、方向性好、能够成为射线而定向传播等特点应用广泛,适合大学生、工程师、技…

精简版Git基础操作(快速上手)

文章目录 前言一、初始化二、新建仓库三、工作区域和文件状态四、添加和提交文件五、回退到之前版本六、查看文件差异七、从版本库中删除文件八、.gitignore忽略文件九、github远程仓库--SSH配置和克隆仓库十、关联本地仓库与远程仓库十一、分支十二、解决合并冲突回退和rebase…

Go mmap 文件内存映射

Go mmap 文件内存映射 mmap是个很好用的内存映射工具,它可以将文件映射到内存中,可以方便地操作文件。使用mmap的优点是: 内存映射可以使得读写文件的性能更高,因为操作的是内存而不是磁盘。可以方便地操作文件,不需…

语音录音转文字的方法使用过吗

大家好!今天我要给你们介绍一个实用的功能,那就是录音转文字啦!它可以把录音中的声音内容快速且准确地转换成文字格式,让我们在工作和学习中变得更加高效和便利。我们在会议记录、采访访谈、语音笔记等领域,可以很大地…

自动化测试之稳定性测试的设计

目录 前言 压力Stress 随机Randomness 并发Concurrency 交互Interaction 时间Time 总结: 前言 稳定性测试是自动化测试领域最为核心的内容之一。稳定性测试设计应该考虑哪些方面?如何在有限的样本上最大化测试产出?笔者结合自动化的一…

Vivado 下 呼吸灯实验

目录 Vivado 下 呼吸灯实验 1、实验简介 2、实验环境 3、实验任务 4、硬件设计 5、程序设计 5.1、呼吸灯代码如下: 5.2、添加约束文件 .xdc 5.3、下载验证 Vivado 下 呼吸灯实验 呼吸灯最早由苹果公司发明并应用于笔记本睡眠提示上,其一经展出&…

2023年6月GESP能力等级认证C++二级真题

2023-06 GESP二级真题 题数:27 分数:100 测试时长:90min 一、单选题(每题 2 分,共 30 分) 1. 高级语言编写的程序需要经过以下( )操作,可以生成在计算机上运行的可执…

电商数仓(用户行为采集平台)数据仓库概念、用户行为日志、业务数据、模拟数据、用户行为数据采集模块、日志采集Flume

1、数据仓库概念 数据仓库( Data Warehouse ),是为企业制定决策,提供数据支持的。可以帮助企业,改进业务流程、提高产品质量等。 数据仓库的输入数据通常包括:业务数据、用户行为数据和爬虫数据等。 业务数…

Linux信号概念、认识、处理动作 ( 2 ) -【Linux通信架构系列 】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 期待你的关注哦!!! 现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。 Now everything is for the…

适合嵌入式开发的GUI(嵌入式学习)

嵌入式开发的GUI如何选择? 常见的嵌入式GUI开发方法轻量级GUI库优缺点 基于Web技术优缺点 Qt框架优缺点 原生开发优缺点 嵌入式系统的限制 常见的嵌入式GUI开发方法 嵌入式开发中的GUI(图形用户界面)是指在嵌入式系统中实现图形化的用户界面…

Unity核心7——2D动画

一、序列帧动画 (一)什么是序列帧动画 ​ 我们最常见的序列帧动画就是我们看的日本动画片,以固定时间间隔按序列切换图片,就是序列帧动画的本质 ​ 当固定时间间隔足够短时,我们肉眼就会认为图片是连续动态的&#…

Pandas数据处理与分析教程:从基础到实战

文章目录 前言什么是Pandas?Pandas的安装和导入数据结构Series(案例1:创建Series)DataFrame(案例2:创建DataFrame) 数据读取和写入从CSV文件中读取数据(案例3:读取CSV文件…

一起学SF框架系列6.2-模块core-Environment

Environment是集成在容器中的抽象接口,它对应用程序环境的两个关键方面进行建模:配置文件(profiles)和属性(properties)。 配置文件(profiles) 配置文件为核心容器中提供了一种机制…

Redis7---单线程和多线程(一)

目录 一、几个面试题 1.Redis的单线程部分 1.2 Redis所谓的“单线程” 1.3 Redis演进变化 1.3.1 Redis 3.x 单线程时代性能很快的原因 1.3.2 Redis 4.0 之前一直采用单线程的主要原因有三个 2. Redis单线程为什么加了多线程特性 3.Redis 6/7的多线程特性和IO多路复用入…

【系统架构】第二章-计算机系统基础知识(一)

计算机硬件 1、处理器:CISC(复杂指令集)、RISC(精简指令集) 2、存储器:按照与处理器的物理距离:片上缓存、片外缓存、主存、外存 3、总线:按照总线在计算机中的位置划分&#xff1a…

大厂流出2023年最新软件测试面试题【全】

1.B/S架构和C/S架构区别 B/S 只需要有操作系统和浏览器就行,可以实现跨平台,客户端零维护,维护成本低,但是个性化能力低,响应速度较慢C/S响应速度快,安全性强,一般应用于局域网中,因…

格雷码转换电路

目录 格雷码转换电路 1、简介 1.2、格雷码转化为二进制码原理如下: 1.3、二进制码转化为格雷码原理如下: 2、实验任务 3、程序设计 3.1、格雷码转换二进制 3.2、二进制转换格雷码 4、仿真测试 5、仿真验证 格雷码转换电路 格雷码,…

推荐一款能够节省办公空间的显示器!

作为一名高校科研人员,课题组师生日常科研工作必备电子设备的维护及更新对于科研进度有着极大影响作用。近日购买了最新一代的戴尔显示器E2424HS。 以下是我的一些真实使用体验: 01 外观高端大气 拆箱前,在检查外包装没有任何破损后&#…

城市道路工程设计技术措施

为在城市道路工程建设中正确执行国家和行业有关法律、标准、规范和规程,提高工程建设质量,特制定《城市道路工程设计技术规程》(2011年版)专门编的。  本办法主要依据国家和行业有关法规、标准、规范和规程等,参照地…

Spring 是什么框架?

对于一门技术,我们需要从为什么要学、学什么以及怎么学这三个方向入手来学习。那在说Spring这三点之前,我们先看Spring之前要学什么。 Java基础、Java语法进阶、MySQL基础操作、MySQL数据库设计和多表操作、JDBC、Maven基础、MyBatis、HMLCSS、JavaScrip…