全网最全synchronized锁升级过程

一、前言

在面试题中经常会有这么一道面试题,谈一下synchronized锁升级过程

之前背了一些,很多文章也说了,到底怎么什么条件才会触发升级,一直不太明白。

实践是检验真理的唯一标准,今天就和大家一起实践一下,什么条件才会升级!

二、为什么会有锁升级过程?

在实践之前,我们先一步步的来了解!为什么要升级呢?

在JDK1.6之前,synchronized的性能一直没有ReentrantLock性能高,主要是因为synchronized涉及到用户态和内核态的切换,这个是在操作系统和硬件是非常消耗资源的。

经过不断的统计分析,发现大部分时间一个锁都是一个线程去获取,如果只有一个线程来尝试加锁,就是重量级锁,显而浪费资源。

总之,锁的升级过程是为了提高多线程环境下的性能和吞吐量,减少同步操作的开销,并尽量避免线程切换的开销。Java虚拟机根据线程竞争的情况和锁的使用情况自动进行锁的升级和降级,以优化多线程程序的性能。

此时,就引入了很多锁类型,下面我们来具体看看!

三、锁分类

偏向锁:偏向锁是为了解决单线程访问的场景,偏向锁允许第一个访问共享资源的线程获得锁,把线程id存到对象头中,后续的访问可以直接获得锁,而不需要竞争。

轻量级锁:当一个或多个线程尝试获取同一个锁时,偏向锁会升级为轻量级锁。轻量级锁采用CAS(Compare and Swap)操作来减小锁的竞争。采用自适应自旋!

重量级锁:操作系统的调度器会介入,将竞争锁的线程挂起,直到锁被释放为止,重量级锁的开销相对较高。

补充:

自适应自旋的基本思想是根据锁的争用情况,决定线程是否应该自旋等待,以及自旋等待的时间,一般情况为自旋10次。

四、对象内存结构

我们在说锁的升级过程之前,需要了解一下对象的内存结构,因为在锁升级过程中会往对象头上进行填充信息!
一个对象分为:对象头、实例数据、对其填充位三部分组成。

在这里插入图片描述

我们本次主要用到对象头,我们在看一下详细的对象头信息里有什么:

在这里插入图片描述

四、图解锁升级过程

先来一个简图:

在这里插入图片描述

下面引用百度上的一张详细一点的图:

在这里插入图片描述

我们来详细的说一下锁的升级过程,在每一个锁切换时的条件是什么?

在JDK8时,偏向锁默认是在程序启动后4s自动开启的,在JKD15之后默认是不开启的!

可以设置无延迟时间启动:-XX:BiasedLockingStartupDelay=0
也可以不启动偏向锁:-XX:-UseBiasedLocking = false

直接说有点不形象,我们下面结合代码来实战,看一下具体情况!

五、实战锁升级过程

为了我们能够查询对象结构,我们需要引入jar帮助我们查看!

1. 导入依赖

注意:不要使用高版本的,高版本不显示2进制,不好观察!

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
</dependency>

2. 实战代码和解析

代码在后面哈

我们来从序号1开始,上面也说了默认4s后开启偏向锁,我们会发现序号1打印的对象头序号为:001
我们的对象大小为20,内部帮我们补位来满足是8的倍数。
方便操作系统进行寻址,不会有碎片组合!这个大家可以详细搜一下,这里就一带而过了哈!

在这里插入图片描述

此时我们睡眠6s,包装偏向锁开启成功!

我们来到序号2,开启了偏向锁,我们发现对象头序号为:101

节点:从无锁到偏向锁切换的条件:JDK8中默认4s后开启,JDK15需要手动开启

在这里插入图片描述
来到序号3和4一起说吧,当我们进行synchronized加锁时,对象的头信息中会记录上当前线程的id,下面再有加锁的,直接判断线程id是否一致,一致直接进入代码块。不一致后面再说!
我们发现在序号4时,已经出了代码块,在此查询加锁的对象,信息依旧在,不会进行移除,这就是偏向,直到下一个线程把上一个替换掉

代码里循环了三次,对象都是一样的!

节点:在只有一个线程访问代码块的时候,对象中会记录当前线程id。

在这里插入图片描述

以上都是在一个线程来访问的情况下

来到序号5,我们新建了一个线程来进行加锁。此时会判断当前线程id和新线程id是否一致,不一致就会认为有竞争关系,会立刻切换为轻量级锁。对象头序号为:00

节点: 当有两个线程交替获取锁时,不存在同时竞争获取锁时。

在这里插入图片描述

序号6和7一起说,我们让上面序号5这个线程获取锁后睡眠3s,持续获得锁。在开启一个新的线程去竞争获取锁,此时先进行自适应CAS自旋,一般10次后一直没办法获取锁,判定为激烈竞争关系。变为重量级锁,序号7线程会进行放到阻塞队列中。对象头序号为:10

经过睡眠后,序号6在此获取对象的信息时,已经变为重量级锁!

节点:有两个及其以上线程同时获取锁,且在自适应自旋范围内没有获取到锁

在这里插入图片描述

下面是代码,大家可以在本地试一下!

/**
 * jvm默认延时4s自动开启偏向锁,
 * 可通过 -XX:BiasedLockingStartupDelay=0
 * 取消延时如果不要偏向锁,可通过-XX:-UseBiasedLocking = false
 * @author wangzhenjun
 * @date 2023/10/18 14:42
 */
public class LockUp {

    @SneakyThrows
    public static void main(String[] args) {

        LockInfo lockInfo = new LockInfo();
        System.out.println("1.无状态:" + ClassLayout.parseInstance(lockInfo).toPrintable());

        Thread.sleep(6000);
        LockInfo lock = new LockInfo();
        System.out.println("2.已经开启了偏向锁模式:" + ClassLayout.parseInstance(lock).toPrintable());

        for (int i = 0; i < 3; i++) {
            synchronized (lock) {
                System.out.println("3.偏向锁模式下,加锁状态:" + ClassLayout.parseInstance(lock).toPrintable());
            }
            System.out.println("4.锁释放了,加锁状态:" + ClassLayout.parseInstance(lock).toPrintable());
        }

        new Thread(() -> {
            synchronized (lock) {
                System.out.println("5.轻量级锁,加锁状态:" + ClassLayout.parseInstance(lock).toPrintable());

                System.out.println("睡眠3s");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("6.轻量级锁=>重量级锁,加锁状态:" + ClassLayout.parseInstance(lock).toPrintable());
            }
        }).start();

        Thread.sleep(1000);

        new Thread(() -> {
            synchronized (lock) {
                System.out.println("重量级锁,加锁状态:" + ClassLayout.parseInstance(lock).toPrintable());
            }
        }).start();

    }
}

六、总结与拓展

经过实战,我们知道了每一个的切换条件,可以在面试中好好的回答了。不至于面试官反问一下就不坚定了!

关于切换到重量级锁后,有兴趣的话,可以下载openJDK源码去看一下关于hotspot/src/share/vm/runtime/objectMonitor.cpphotspot/src/share/vm/runtime/objectMonitor.hpp

源码下载地址

objectMonitor.cpp:是 OpenJDK 中实现 Java 同步机制的核心部分,它负责管理对象监视器,确保多线程程序能够正确协同工作,实现线程同步和等待/通知机制

在这里插入图片描述

objectMonitor.hpp:主要用于定义对象监视器的接口和数据结构,为实际的对象监视器的实现提供了基础

在这里插入图片描述


看到这里了,还请动一下您的发财小手,关注一下公众号哈!!谢谢您的关注!!文章首发看!!!

建了一个IT交流群,欢迎大家加入,过期加我拉你们进哈!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

kafka+ubuntu20.04+docker配置

记录一次配置过程 安装docker 参加下面链接的第一部分 Ubuntu20.04使用docker安装kafka服务-CSDN博客 安装zookeeper docker run -d --name zookeeper -p 2181:2181 -v /etc/localtime:/etc/localtime wurstmeister/zookeeper安装kafka服务 docker run -d --name kafka …

react路由安装配置react-router-dom/‘Switch‘ is not defined报错解决

1.安装 npm install --save react-router-dom安装完成 新建两个页面并导出 app.js import Nav from ./components/Nav import Home from ./components/Home import { Link, Route, Switch } from react-router-domfunction App() {return (<div><div><p>&…

【2021集创赛】Arm杯一等奖作品—基于 Cortex-M3 内核 SOC 的动目标检测与跟踪系统

本作品介绍参与极术社区的有奖征集|秀出你的集创赛作品风采,免费电子产品等你拿~ 团队介绍 参赛单位&#xff1a;北京理工大学 队伍名称&#xff1a;飞虎队 指导老师&#xff1a;李彬 参赛杯赛&#xff1a;Arm杯 参赛人员&#xff1a;余裕鑫 胡涵谦 刘鹏昀 获奖情况&#xff1…

使用责任链模式实现登录风险控制

责任链模式 责任链模式是是设计模式中的一种行为型模式。该模式下&#xff0c;多个对象通过next属性进行关系关联&#xff0c;从而形成一个对象执行链表。当发起执行请求时&#xff0c;会从首个节点对象开始向后依次执行&#xff0c;如果一个对象不能处理该请求或者完成了请求…

侧击雷如何检测预防

侧击雷是一种雷击的形式&#xff0c;指的是雷电从建筑物的侧面打来的直接雷击。侧击雷对高层建筑物的防雷保护提出了更高的要求&#xff0c;因为一般的避雷带或避雷针不能完全保护住建筑物的侧面。侧击雷可能会对建筑物的结构、设备和人员造成严重的损害&#xff0c;甚至引发火…

酷开科技丨酷开系统,带你进入惊喜不断的影视世界!

随着科技的迅速发展&#xff0c;智能电视已经成为家庭娱乐的重要组成部分。而要说到智能电视&#xff0c;就不得不提到酷开系统&#xff0c;作为一款智能电视操作系统&#xff0c;酷开系统以其独特的功能和出色的使用体验&#xff0c;让观众们看到了到惊喜不断的影视世界。 如…

CRM系统:助力数据服务企业,打造核心竞争力

近年来&#xff0c;数据服务企业开始走入大众视野。作为企业管理应用热门选手——CRM客户管理系统&#xff0c;可以助力企业实时数据应用先行者&#xff0c;提升业务转化与协同效率&#xff0c;进一步打造核心竞争力。下面我们说说&#xff0c;CRM系统对数据服务企业的作用。 …

Stable Diffusion 是否使用 GPU?

在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 3D数字孪生场景编辑器 Stable Diffusion 已迅速成为最流行的生成式 AI 工具之一&#xff0c;用于通过文本到图像扩散模型创建图像。但是&#xff0c;它需…

使用 Stable Diffusion Img2Img 生成、放大、模糊和增强

在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 3D数字孪生场景编辑器 Stable Diffusion 2022.1 Img5Img 于 2 年发布&#xff0c;是一款革命性的深度学习模型&#xff0c;正在重新定义和推动照片级真实…

云原生Kubernetes系列 | 通过容器互联搭建wordpress博客系统

云原生Kubernetes系列 | 通过容器互联搭建wordpress博客系统 通过容器互联搭建一个wordpress博客系统。wordpress系统是需要连接到数据库上的&#xff0c;所以wordpress和mysql的镜像都是需要的。wordpress在创建过程中需要指定一些参数。创建mysql容器时需要把mysql的数据保存…

linux系统下文件操作常用的命令

一、是什么 Linux 是一个开源的操作系统&#xff08;OS&#xff09;&#xff0c;是一系列Linux内核基础上开发的操作系统的总称&#xff08;常见的有Ubuntu、centos&#xff09; 系统通常会包含以下4个主要部分 内核shell文件系统应用程序 文件系统是一个目录树的结构&…

PyQt中QFrame窗口中的组件不显示的原因

文章目录 问题代码&#xff08;例&#xff09;原因和解决方法 问题代码&#xff08;例&#xff09; from PyQt5.QtWidgets import * from PyQt5.QtGui import QFont, QIcon, QCursor, QPixmap import sysclass FrameToplevel(QFrame):def __init__(self, parentNone):super().…

【Python基础篇】变量

博主&#xff1a;&#x1f44d;不许代码码上红 欢迎&#xff1a;&#x1f40b;点赞、收藏、关注、评论。 格言&#xff1a; 大鹏一日同风起&#xff0c;扶摇直上九万里。 文章目录 一 Python中变量的定义二 Python中变量的使用三 Python中变量的类型四 Python中变量的删除五 …

[数据结构大作业]HBU 河北大学校园导航

校园导航实验报告 问题描述&#xff1a; 以我校为例&#xff0c;设计一个校园导航系统&#xff0c;主要为来访的客人提供信息查询。系统有两类登陆账号&#xff0c;一类是游客&#xff0c;使用该系统方便校内路线查询&#xff1b;一类是管理员&#xff0c;可以使用该系统查询…

mysql常用命令-03

今天讲解下mysql中创建表的语法 CREATE TABLE tb_name( 列名 数据类型 [PRIMARY KEY] [AUTO_INCREMENT], 列名 数据类型 [NULL | NOT NULL], ....., 列名 数据类型 ); 1.创建班级表classes,结构如下&#xff1a; 列名数据类型允许空约束其它说明cid INT主键班级编号cname…

医疗器械维修工程师必须重视的方面

彩虹医疗器械维修技能培训开班报名中 长期班低至五折&#xff0c; 打破常规培训模式轻松愉快技术学习&#xff01; 两个多月时间&#xff0c;提升自我&#xff01; 点击进入 彩虹实训基地 理论实践结合教学 小班授课 立即咨询 1 工程师须重视 在医疗行业中&#xff0c;…

【算法与数据结构】46、47、LeetCode全排列I, II

文章目录 一、46.全排列I二、47.全排列II三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、46.全排列I 思路分析&#xff1a;本题要求是全排列&#xff0c;意味着每次递归的时候startIndex都要从0开始&#xff0c;否则…

mysq,数据库的综合查询

记录一下数据库综合查询&#xff0c;复习加深印象 创建教学数据库中包含四个基本表&#xff1a; 教师情况表Teacher&#xff08;Tno 教师号&#xff0c;TName 教师名&#xff0c;TDept 教师所在的院系&#xff09;&#xff1b;课程基本表Course&#xff08;Cno 课号&#xff…

LeetCode(12)时间插入、删除和获取随机元素【数组/字符串】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 380. O(1) 时间插入、删除和获取随机元素 1.题目 实现RandomizedSet 类&#xff1a; RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时&#xff0c;向集合中插入该项&#xff0c;并返回…

CSS 实现新拟态(Neumorphism) UI 风格

什么是新拟态(Neumorphism) UI 风格&#xff1f;网上似乎还没有一个准确统一的定义。按照我个人的通俗理解&#xff0c;就是将界面的一部分凸起来&#xff0c;另一部分凹下去&#xff0c;形成的一种错落有致的拟物风格。代表作是乌克兰设计师 Alexander Plyuto 在各平台发布的新…