全网最全synchronized锁升级过程

news2024/10/6 0:30:37

一、前言

在面试题中经常会有这么一道面试题,谈一下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交流群,欢迎大家加入,过期加我拉你们进哈!

在这里插入图片描述

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

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

相关文章

uniapp+vite+vue3开发跨平台app,运行到安卓模拟器调试方法

因为没有使用hbuilder开发uniapp&#xff0c;而是使用了vscode和vite来开发的&#xff0c;所以怎么将这个程序运行到安卓模拟器调试开发呢&#xff1f;其实方法很简单&#xff0c;使用android studio创建一个模拟器或者其他mumu模拟器&#xff0c;然后将项目使用hbuilder打开&a…

空间数据结构笔记:层次包围盒树(Bounding Volume Hierarchy Based On Tree)

1 总览 层次包围盒树&#xff08;BVH树&#xff09;是一棵多叉树&#xff0c;用来存储包围盒形状。它的根节点代表一个最大的包围盒&#xff0c;其多个子节点则代表多个子包围盒。为了统一化层次包围盒树的形状&#xff0c;它只能存储同一种包围盒形状 2 AABB包围盒树&#x…

Web安全:Vulfocus 靶场搭建.(漏洞集成平台)

Web安全&#xff1a;Vulfocus 靶场搭建.&#xff08;漏洞集成平台&#xff09; Vulfocus 是一个包含了多种漏洞靶场的镜像。每个靶场都有具体的漏洞环境和攻击点。Vulfocus 的靶场包括了 Web 安全漏洞、系统安全漏洞、网络安全漏洞、密码学漏洞等多种类型。通关这个靶场我们可以…

日出日落的气象意义:探索日出日落查询API在天气预测中的应用

引言 当谈论气象意义时&#xff0c;日出和日落都是天文现象中的重要组成部分。它们不仅是自然界美妙的展示&#xff0c;更对天气预测有着深远的影响。而如今&#xff0c;随着科技的发展&#xff0c;日出日落查询API在天气预测中的应用正在变得越来越重要。 日出和日落的气象意…

Q learning

Q learning Q Learning是强化学习算法中的一个经典算法。在一个决策过程中&#xff0c;我们不知道完整的计算模型&#xff0c;所以需要我们去不停的尝试。 算法流程 整体流程如下&#xff1a; Q-table 初始化 第一步是创建 Q-table&#xff0c;作为跟踪每个状态下的每个动作…

linux 系统下文本编辑常用的命令

一、是什么 Vim是从 vi 发展出来的一个文本编辑器&#xff0c;代码补全、编译及错误跳转等方便编程的功能特别丰富&#xff0c;在程序员中被广泛使用。 简单的来说&#xff0c; vi 是老式的字处理器&#xff0c;不过功能已经很齐全了&#xff0c;但是还是有可以进步的地方 而…

苹果手机通话记录怎么恢复?这3个方法就足够!

通话记录是手机中的重要数据之一&#xff0c;它记录了用户与联系人的通话信息&#xff0c;包括通话时间、通话时长、通话号码等等。 有时候&#xff0c;我们可能不小心删除了通话记录&#xff0c;或者想找回之前的通话记录以此来回忆起一些事情。那么&#xff0c;苹果手机通话…

全自动内衣洗衣机什么牌子好?家用迷你洗衣机推荐

内衣洗衣机是一种专为内衣、丝绸和其他精细衣物设计的家电&#xff0c;它们能够温柔地清洁和保护这些特殊材质的衣物。代替了传统的手洗&#xff0c;能够大大节约我们不少的宝贵时间。但在市场上&#xff0c;有各种型号和功能的内衣洗衣机&#xff0c;如何挑选到一款适合自己的…

内衣洗衣机怎么选?小型洗衣机质量排名

现在大部分的家庭都拥有高质量、大品牌、大容量的洗烘套装来满足一家人的日常洗烘需要&#xff0c;像内衣这种贴身的衣物&#xff0c;需要手洗或者用专用的内衣洗衣机&#xff0c;这样才可以最大程度地减少细菌的交叉感染&#xff0c;提高我们贴身衣物的卫生&#xff0c;那么怎…

深入浅出理解Android开发框架中的MVC、MVP和MVVM模式

✍️作者简介&#xff1a;沫小北/码农小北&#xff08;专注于Android、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a;沫小北/码农小北 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&…

【React】Antd 组件基本使用

Antd 组件基本使用 第一步 安装并引入 antd 包 使用命令下载这个组件库 yarn add antd在我们需要使用的文件下引入&#xff0c;我这里是在 App.jsx 内引入 import { Button } from antd现在我们可以在 App 中使用 Button 组件 <div>App..<Button type"prima…

成都瀚网科技有限公司抖音带货的靠谱之选

随着电子商务的飞速发展&#xff0c;越来越多的商家开始利用网络平台进行产品销售。这其中&#xff0c;抖音作为一款广受欢迎的短视频平台&#xff0c;其带货能力不容小觑。然而&#xff0c;在选择抖音带货服务商时&#xff0c;很多商家会面临困惑&#xff1a;成都瀚网科技有限…

易基因:MeRIP-seq+ChIP-seq等揭示m6A甲基化在休眠期转录休眠调控中的潜在功能 | 发育研究

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 发育通常被认为是遗传程序的顺序展开&#xff0c;复杂程度不断提高&#xff0c;并按固定轨迹随时间进行。然而&#xff0c;调整发育时间可以提高在不利条件下的存活率。在哺乳动物中&…

Istio学习笔记-部署模型

参考&#xff1a;Istioldie 1.18 / 部署模型 当您将 Istio 用于生产环境部署时&#xff0c;需要确定一系列的问题。 网格将被限制在单个集群中还是分布在多个集群中&#xff1f; 是将所有服务都放置在单个完全连接的网络中&#xff0c;还是需要网关来跨多个网络连接服务&#…

开源会议通知H5页面邀请函制作源码系统+自动翻页 带完整的搭建教程

现如今&#xff0c;线上活动越来越频繁&#xff0c;而会议邀请函也成为了活动组织者不可或缺的工具。然而&#xff0c;传统的邮件、短信等方式发送邀请函已经无法满足现代人的需求。因此&#xff0c;开发一款现代化的、功能丰富的会议邀请函系统势在必行。下面源码小编将来给大…

检索搜索信息能力

&#xff08;一&#xff09;搜索工具的选择 谷歌 > 微信搜一搜 > 抖音等短视频 > 百度 &#xff08;二&#xff09;搜索方式 一&#xff0c;搜索内容的分类 信息类学习类工具类 二&#xff0c;谷歌浏览器的搜索技巧 1、“搜索内容” 限定完整出现的词 如下图搜…

酒店数据抓取

好的&#xff0c;以下是使用Haskell编写的一个简单的网页爬虫程序&#xff0c;用于抓取Booking.com和云地接酒店数据的示例。这个程序使用HTTP代理&#xff0c;代理信息为proxy_host: jshk.com.cn。 import Network.HTTP import Network.HTTP代理 import Network.URImain :: I…

二蛋赠书八期:《Java物联网、人工智能和区块链编程实战》

前言 大家好&#xff01;我是二蛋&#xff0c;一个热爱技术、乐于分享的工程师。在过去的几年里&#xff0c;我一直通过各种渠道与大家分享技术知识和经验。我深知&#xff0c;每一位技术人员都对自己的技能提升和职业发展有着热切的期待。因此&#xff0c;我非常感激大家一直…

【uniapp】确认弹出框,选择确定和取消

代码如下&#xff1a; <view style"display: flex; justify-content: space-around;"><button class"button" click"submit">t提交</button> </view>submit(){let thatthisuni.showModal({title: 提示&#xff1a;,con…

Shell脚本 CPU,内存,磁盘占用率检测

CPU&#xff1a;运算资源占用 内存&#xff1a;RAM类介质 磁盘&#xff1a;ROM类介质 一、CPU #!/bin/bash# 设置阈值&#xff0c;当CPU占用超过该阈值时进行输出提示 threshold80while true do# 使用top命令获取CPU占用信息&#xff0c;并使用grep和awk筛选和解析输出结果…