Synchronized的实现和锁升级

news2025/1/11 23:03:23

1.JVM是如何处理和识别Synchronized的?

我们从字节码角度分析synchronized的实现:

  1. Synchronized(锁对象){}同步代码块底层实现方式是monitorentermonitorexit指令。

  2. 修饰普通同步方法时底层实现方式是执行指令会检查方法是否设置ACC_SYNCHRONIZED,如果设置了,则会先持有monitor锁(其实就是管程,锁对象),然后在执行方法,最后释放锁(无论方法执行完或出现异常)。

  3. 修饰静态同步方法时底层实现方式是执行指令会检查方法是否同时设置ACC_STATIC和ACC_SYNCHRONIZED,ACC_STATIC也用于分辨锁是类锁还是对象锁

2.为什么任何一个类的对象都可以成为锁对象?

        在HotSpot虚拟机中,监视器monitor采用的是ObjectMonitor实现的,在Java中,Object是每个类的父类,所以每个对象天生都带着一个对象监视器。在ObjectMonitor.java源代码中我们发现里面调用了objectMonitor.cpp文件,在objectMonitor.cpp里面又调用了ObjectMonitor.hpp,而在hpp文件中很明确的记录了正在持有此锁的线程、锁的重入次数等数据。

 

3.Synchronized锁的升级

Synchronized锁的状态主要依赖对象头中的MarkWord中锁标志位偏向锁位

3.1下面我们就表述锁升级的过程(重点)

        初始状态下,一个对象被实例化后,如果还没有任何线程使用此锁,那么它就为无锁状态(偏向锁位为0,锁标志位为01),当线程A第一次占用此锁时,MarkWord中会记录线程A的线程id,然后升级为偏向锁(偏向锁位为1,锁标志位为01),然后下一个线程访问时,会看MarkWord中记录的线程id是否和访问的线程一致,如果一致,就相当于还是线程A一直在访问,那么就会自动的获取锁,无需每次CAS去更新对象头,但是如果发现线程的id不一致,那么就发生了竞争,比如线程B来访问了,发现MarkWord中记录的线程id和自己的不一致,那么就会尝试使用CAS来替换MarkWord里面的线程id为自己线程B的线程id,如果修改竞争成功了,那么ok,MarkWord里面的线程idA更换为线程B的id,锁不会升级,还是偏向锁,但是如果线程B修改竞争失败,那么锁的状态就需要发生改变了,首先就是要先撤销偏向锁,先等待全局的安全点(STW),同时检查正持有偏向锁的线程A执行到哪里了,如果说线程A正在处于同步代码块中,相当于线程A还没有执行完,那么会将锁升级为轻量锁(偏向锁位为0,锁标志位为00),线程A继续执行同步代码块,而正在竞争的线程B会自动进行自旋。但如果说线程A刚好执行完同步代码块,此时会设置为无锁的状态,线程A,B会同时开始竞争。如下图:

 ​​​​​​

        假如此时锁升级为了轻量级锁,JVM会在每个线程的栈帧中创建用于存储锁记录的空间(Displaced Mark Word),若此时线程A想要获取轻量级锁,会把锁对象的MarkWord拷贝复制到自己的DMW里面,然后线程A再尝试利用CAS将锁对象中的MarkWord中的指向记录改为指向线程A栈中的Lock Record的指针,此时如果线程A的CAS失败了,就说明线程B正在占用此锁,线程A就会通过不断自旋来获取锁,等到线程B执行完后,线程B还要将轻量级锁释放,线程B使用CAS操作将DMW的内容重新复制回锁对象的Mark Word里面。如果此时有大量的线程涌入,参与竞争,一个线程自旋到一定的次数,锁就会会升级为重量级锁(偏向锁位为0,锁标志位为10),没拿到锁的线程会等待操作系统的调动,就不在主动的去抢占获取锁了。具体这个自旋次数在Java8之后是自适应自旋锁。

  • 线程如果自旋成功了,那下次自旋的最大次数会增加,因为JVM认为既然上次成功了,那么这一次也大概率会成功

  • 如果很少会自选成功,那么下次会减少自旋的次数甚至不自旋,避免CPU空转。

3.2几个需要说明的小问题?

1.JDK15废除了偏向锁

JDK15以后逐步废弃偏向锁,需要手动开启------->因为维护成本高。

2.MarkWord中指向记录在不同状态的指向不同

  • 偏向锁:MarkWord存储的是偏向的线程ID

  • 轻量锁:MarkWord存储的是指向线程栈中Lock Record的指针

  • 重量锁:MarkWord存储的是指向堆中锁的Monitor(监视器)对象,修改里面的owner来实现。

3.无锁会默认到偏向锁

实际上无锁是默认会自动升级为偏向锁的,但是启动时间有延迟,可以通过添加参数,让其在程序启动时立即启动。

4.锁升级后,hashcode去哪里了?

我们可以发现,hashcode值的位置和锁指向的内存位置会冲突,那么内部是怎么解决的呢——>

  • 在无锁的状态下,对象的hashcode()值存储在Mark Word中,此时它就再也无法进入到偏向锁状态了。

  • 如果已经在偏向锁状态下,才调用hashcode()方法,偏向锁的状态会被立即取消,锁会膨胀为重量级锁。

  • 在轻量级锁状态下,会在DMW中保存拷贝的Mark Word的值,释放锁后,会将这些信息重新写回到对象头的Mark Word中(相当于覆盖了)。

  • ObjectMonitor类里面有字段会记录非加锁状态下的Mark Word,锁释放后也会重新写回到对象头中的Mark Word中。

3.3JIT编译器对锁的优化

JIT对锁的优化分为锁消除和锁粗化,其实这两个概念挺乏味的。

3.3.1锁消除

简单来说就是,如果每个线程都拥有一把锁,那么我们写的加锁代码就毫无意义了,从JIT角度来看就是无视它了,消除了对锁的使用。示例代码:

public class LockClearUpDemo {
    static Object object = new Object();

    public void m1() {
        //锁消除问题,JIT会无视它,synchronized(o)每次new出来的,加锁就无意义了
        Object o = new Object();
        synchronized (o) {
            System.out.println("-----------hello LockClearUpDemo" + "\t" + o.hashCode() + "\t" + object.hashCode());
        }
    }

    public static void main(String[] args) {
        LockClearUpDemo lockClearUpDemo = new LockClearUpDemo();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                lockClearUpDemo.m1();
            }, String.valueOf(i)).start();
        }
    }
}

3.3.2锁粗化

如方法中多个同步块首尾相接,前后使用的都是同一个锁对象,那么JIT编译器会把这几个synchronized块合并为一个大块,加粗锁的范围。

public class LockBigDemo {
    static Object objectLock = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (objectLock) {
                System.out.println("111111111111");
            }
            synchronized (objectLock) {
                System.out.println("222222222222");
            }
            synchronized (objectLock) {
                System.out.println("333333333333");
            }
            synchronized (objectLock) {
                System.out.println("444444444444");
            }
            //底层JIT的锁粗化优化
            synchronized (objectLock) {
                System.out.println("111111111111");
                System.out.println("222222222222");
                System.out.println("333333333333");
                System.out.println("444444444444");
            }
        }, "t1").start();
    }
}

4.Synchronized的具体实现

        线程代码进入到Synchronized代码块时会自动获取锁对象,这时其他线程访问时会被阻塞,直到Synchroinzed代码块执行完毕或抛出异常,调用wait()方法都会释放锁对象。在进入Synchronized代码块时会将主内存的变量读取到自己的工作内存,在退出的时候会把工作内存的更新值写入到主内存。Java中Synchronized通过在锁对象的对象头设置标记,达到获取锁和释放锁的目的。

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

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

相关文章

11个在线免费调整图像大小而不会降低质量工具

图片对于增强您的网站、博客和其他在线平台的视觉效果非常重要&#xff0c;而这些图片的正确尺寸在这里起着重要作用。如果您有多种尺寸的图像并且想要调整为一个尺寸&#xff0c;可以使用多种在线图像调整工具。使用在线工具&#xff0c;没有软件下载或安装的麻烦&#xff0c;…

比较常见的在线项目管理系统有哪些?

在线项目管理系统作为一个适用于各领域任务管理、工时收集、团队协作与即时沟通的企业级在线项目管理解决方案&#xff0c;可以为用户同时协调和管理数以百计的项目和团队成员&#xff0c;而软件所具有的成熟&#xff0c;可靠和友好特性&#xff0c;将不再让用户在易用性和功能…

论文阅读--Energy efficiency in heterogeneous wireless access networks

异构无线接入网络的能源效率 论文信息&#xff1a;Navaratnarajah S, Saeed A, Dianati M, et al. Energy efficiency in heterogeneous wireless access networks[J]. IEEE wireless communications, 2013, 20(5): 37-43. I. ABSTRACT && INTRODUCTION 本文提出了无…

Holographic MIMO Surfaces (HMIMOS)以及Reconfigurable Holographic Surface(RHS)仿真

这里写目录标题 Simulation setupchatgpt帮我总结代码 Holographic MIMO Surfaces &#xff08;HMIMOS&#xff09;以及Reconfigurable Holographic Surface&#xff08;RHS&#xff09;仿真&#xff1a; Simulation setup In this section, we evaluate the performance of …

香橙派、树莓派、核桃派、鲁班猫安装jupyter notebook【ubuntu、Debian开发板操作类似】

文章目录 前言一、安装环境二、使用方法总结 前言 香橙派树莓派鲁班猫安装一下调试代码还是比较方便的。 一、安装环境 假设已经安装好了miniconda3。如果还没安装可以参考我另外一篇博文&#xff0c;有写怎么安装。 pip install jupyter notebook # 生成Jupyter Notebook的…

【密评】商用密码应用安全性评估从业人员考核题库(四)

商用密码应用安全性评估从业人员考核题库&#xff08;四&#xff09; 国密局给的参考题库5000道只是基础题&#xff0c;后续更新完5000还会继续更其他高质量题库&#xff0c;持续学习&#xff0c;共同进步。 751 判断题 HMAC是一种消息鉴别码。 正确 错误 752 多项选择题 …

基于PSD-ML算法的语音增强算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 1.加窗处理&#xff1a; 2.分帧处理&#xff1a; 3.功率谱密度估计&#xff1a; 4.滤波处理&#xff1a; 5.逆变换处理&#xff1a; 6.合并处理&#xff1a; 5.算法完整程序工程 1.算法…

使用Java语言深度探索数据结构中的单向链表:完美结合详解与示例代码

版本说明 当前版本号[20231007]。 版本修改说明20231007初版 目录 文章目录 版本说明目录2.2 链表1) 概述定义简单分类随机访问性能插入或删除性能 2) 单向链表头部添加循环遍历while遍历for 遍历迭代器遍历匿名内部类转换为带名字的内部类 尾部添加递归遍历 根据索引获取寻…

HTML 笔记:初识 HTML(HTML文本标签、文本列表、嵌入图片、背景色、网页链接)

1 何为HTML 用来描述网页的一种语言超文本标记语言(Hyper Text Markup Language)不是一种编程语言&#xff0c;而是一种标记语言 (markup language) 2 HTML标签 HTML 标签是由尖括号包围的关键词&#xff0c;比如 <html> 作用是为了“标记”页面中的内容&#xff0c;使…

群晖搭建docker系统和办公服务2

首先先确认下我们的Office是否为VOL版&#xff0c;方法如下&#xff08;请您根据自身情况更改以下命令&#xff09;&#xff1a; 管理员身份运行命令提示符&#xff0c;输入 cd C:\Program Files\Microsoft Office\Office16 切换目录 &#xff08;这里请根据您自己的Office版本…

golang gin——中间件编程以及jwt认证和跨域配置中间件案例

中间件编程jwt认证 在不改变原有方法的基础上&#xff0c;添加自己的业务逻辑。相当于grpc中的拦截器一样&#xff0c;在不改变grpc请求的同时&#xff0c;插入自己的业务。 简单例子 func Sum(a, b int) int {return a b }func LoggerMiddleware(in func(a, b int) int) f…

【轻松玩转MacOS】外部设备篇

引言 在开始之前&#xff0c;我们先来了解一下为什么要连接外部设备。想象一下&#xff0c;你正在享受MacOS带来的便捷和高效&#xff0c;突然需要打印一份文件&#xff0c;但你发现打印机无法连接&#xff1b;或者你需要将手机投屏到电脑上&#xff0c;却不知道该如何操作。这…

在模拟器上安装magisk实现Charles抓https包(二)

在上一篇在模拟器上安装magisk实现Charles抓https包&#xff08;一&#xff09;_小小爬虾的博客-CSDN博客&#xff0c;好不容易在模拟器上安装好了Magisk&#xff0c;本篇记录安装movecert模块和AlwaysTrustUserCerts模块。 这两个模块的功能都是将Charles等证书从用户目录转移…

【ARM CoreLink 系列 1 -- SoC 片上互联介绍】

文章目录 概述1.1 片上互连架构的发展1.1.1 BUS 共享总线结构1.1.2 Crossbar 结构1.1.3 Ring 结构1.1.4 Mesh 网格结构 1.2 ARM 总线互联特点小结1.2.1 NOC 总线互联的特点 下篇文章&#xff1a;【ARM CoreLink 系列 1.1 – CoreLink 系列 产品介绍】 概述 在摩尔定律的推动下…

二叉树实现快速查找数字所在区间

背景 通过IP地址查询ip地址所属省市&#xff0c;存在这样的数据 3748137472,3748137727,223.104.10.0,223.104.10.255,中国,江西,,,移动,330000,,城域网 3748137728,3748137983,223.104.11.0,223.104.11.255,中国,陕西,,,移动,710000,,移动网络 3748137984,3748138239,223.104…

1.7 计算机网络体系结构

思维导图&#xff1a; 1.7.1 计算机网络的体系结构的形成 **1.7 计算机网络体系结构** 计算机网络体系结构中&#xff0c;分层的思想为核心。该方法使得复杂的网络设计变得更为简单和可管理。 **1.7.1 计算机网络体系结构的形成** - **计算机网络的复杂性**: 即使是简单的文…

2.4 信道复用技术

前言&#xff1a; 2.4.1 频分复用、时分复用和统计时分复用 **2.4 信道复用技术笔记** --- **1. 定义&#xff1a;** - **复用 (Multiplexing)**&#xff1a;允许多个用户共享一个传输介质&#xff0c;从而提高资源使用效率。 --- **2. 基本复用示意&#xff1a;** - 使用…

SQL进阶 - SQL的编程规范

性能优化是一个很有趣的探索方向&#xff0c;将耗时耗资源的查询优化下来也是一件很有成就感的事情&#xff0c;但既然编程是一种沟通手段&#xff0c;那每一个数据开发者就都有义务保证写出的代码逻辑清晰&#xff0c;具有很好的可读性。 目录 引子 小试牛刀 答案 引言 …

互联网图片安全风控实战训练营开营!

内容安全风控&#xff0c;即针对互联网产生的海量内容的外部、内部风险做宏观到微观的引导和审核&#xff0c;从内容安全领域帮助企业化解监管风险和社会舆论风险&#xff0c;其核心是识别文本、图片、视频、音频中的有害内容。 由于互联网内容类型繁杂、多如牛毛&#xff0c;加…

mysql面试题22:SQL优化的一般步骤是什么,怎么看执行计划(explain),如何理解其中各个字段的含义

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:SQL优化的一般步骤是什么,怎么看执行计划(explain),如何理解其中各个字段的含义 SQL优化的一般步骤如下: 分析和理解问题:首先,要确保对问…