synchronized进阶原理

news2024/11/23 21:45:14

synchronized进阶原理

1.轻量级锁

轻量级锁的使用场景:如果一个对象虽然有多个线程访问,但多线程访问的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化(如果出现竞争,操作系统会将轻量级锁升级为重量级锁)。轻量级锁对使用者是透明的(由操作系统控制),即语法仍是synchronized。

假设有两个方法同步块,利用同一个对象加锁

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

创建锁记录(Lock Record)对象,每个线程的栈帧都会包含一个锁记录的结构,内部可以存储锁定对象的Mark Word

在这里插入图片描述

让锁记录中Object reference 指向锁对象,并尝试用cas替换Object的Mark Word,将Mark Word的值存入锁记录(01代表未上锁,00代表上轻量级锁)

在这里插入图片描述

如果cas替换成功,对象头中存储了锁记录地址和状态00,表示由该线程给对象加锁

在这里插入图片描述

如果cas失败,有两种情况

· 如果其它线程已经持有了该Object的轻量级锁,这时表明有竞争,进入锁膨胀过程

· 如果是自己执行了synchronized锁重入(自己又对synchronized加锁了),那么再添加一条Lock Record作为重入的计数

在这里插入图片描述

当退出synchronized代码块(解锁时)如果有取值为null的锁记录,表示有重入,这时重置锁记录,表示重入计数减一

在这里插入图片描述

当退出synchronized代码块(解锁时)锁记录的值不为null,这时使用cas将Mark Word的值恢复给对象头

· 成功,则解锁成功

· 失败,说明轻量级锁进行了膨胀或已经升级为重量级锁,进入重量级锁解锁流程

2.锁膨胀

如果在尝试加轻量级锁的过程中,CAS操作无法成功,这时一种情况就是有其他线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁变为重量级锁。

static Object obj = new Object();
public static void method1(){
    synchronized(obj){
        //同步块
    }
}

当Thread-1进行轻量级锁时,Thread-0已经对该对象加了轻量级锁

在这里插入图片描述

这时Thread-1加轻量级锁失败,进入锁膨胀流程

· 即为Object对象申请Monitor锁,让Object指向重量级锁地址

· 然后自己进入Monitor的EntryList中 BLOCKED

在这里插入图片描述

当Thread-0退出同步代码块解锁时,使用cas将Mark Word的值恢复给对象头,失败。这时会进入重量级解锁流程,即按照Monitor地址找到Monitor对象,设置Owner为null,唤醒EntryList中BLOCKED线程,从它们中竞争出下一个与Owner关联的线程

3.自旋优化

重量级锁竞争的时候,还可以使用自旋锁来进行优化,如果当前线程自旋锁成功(即这时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。

自选重试成功的情况

在这里插入图片描述

自旋重试失败的情况

在这里插入图片描述

在java6之后自旋锁是自适应的,比如对象刚刚的一次自旋操作成功过,那么认为这次自旋成功的可能性会高,就多自旋几次;反之,就少自旋甚至不自旋。自旋会占用CPU时间,单核CPU自旋就是浪费,多核CPU自旋才能发挥优势。java7之后不能控制是否开启自旋功能。

4.偏向锁

轻量级锁在没有竞争时(就自己这个线程),每次重入仍需要执行CAS操作。java6中引入了偏向锁来做进一步优化:只有第一次使用CAS将线程ID设置到对象的Mark Word头,之后发现这个线程ID是自己的就表示没有竞争,不用重新CAS。以后只要不发生竞争,这个对象就归该线程所有。

static final Object obj = new Object();
public static void m1(){
    synchronized(obj){
        //同步块A
        m2();
    }
}
public static void m2(){
    synchronized(obj){
        //同步块B
        m3();
    }
}
public static void m3(){
    synchronized(obj){
        //同步块C
    }
}

在这里插入图片描述

在这里插入图片描述

偏向状态

对象头:

在这里插入图片描述

biased_lock 用于记录是否启动偏向锁(0为未启动)

thread 是线程id(操作系统给的,和java中自己设置的不同)

一个对象创建时:

· 如果启动了偏向锁(默认开启),那么对象创建后,markword值为0x05即最后3位为101,这时它的thread、epoch、age都是0

· 偏向锁默认是延迟的,不会在程序启动时立即生效,如果想避免延迟,可以加VM参数 - XX:BiasedLockingStartupDelay=0来禁止延迟

· 如果没有开启偏向锁,那么对象创建后,markword值为0x01即最后3位为001,这时它的hashcode、age都为0,第一次用到hashcode时才会赋值

测试禁用:在上面测试代码运行时在添加VM参数 -XX: -UseBiasedLocking 禁用偏向锁

测试hashCode:当对用对象的hashCode()时,偏向锁会被撤销,对象就会变成普通状态(当轻量级锁对象调用hashCode()时,hashCode会记录在栈帧中的锁记录里,当重量级锁调用hashCode()时,hashCode会存在monitor对象里)

撤销偏向锁-其它线程使用对象

当有其他线程使用偏向锁对象时,会将偏向锁升级为轻量级锁。

撤销偏向锁-使用wait/notify

批量重偏向

如果对象虽然被多个线程访问,但没有竞争,这时偏向了线程T1的对象仍有机会重新偏向T2,重偏向会重置对象的Thread ID

当撤销偏向锁阈值超过20次后,JVM会在给这些对象加锁时重新偏向至加锁线程。

批量撤销

当撤销偏向锁阈值超过40次后,JVM会觉得不该偏向。于是整个类的所有对象都会变为不可偏向的,新建的对象也是不可偏向的。

锁撤销

java有即时编译器(JIT),会对代码进行优化,将一些无用的锁优化掉了

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

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

相关文章

JavaWeb——Web入门(3/9)-HTTP协议:概述(概念、特点,HTTP协议定义,基于 TCP 协议,基于请求-响应模型)

目录 概念 特点 内容预告 概念 HTTP 协议定义:全称 Hyper Text Transfer Protocol,即超文本传输协议,规定了浏览器与服务器之间数据传输的规则,具体指客户端浏览器与服务器之间进行数据交互的数据格式。 在互联网的世界中&…

Altium Designer使用技巧(二)

一、创建类 1、按DC键,打开对象类。 2、右键添加一个类。命名为PWR。 3、将所有的电源类,全部添加到新创建的类中,从非成员类中点选到成员类中。 4、右下角点panes ,点PCB。 5、然后在左边单击PWR,点连接,可显示或…

边缘计算【智能+安全检测】系列教程--agx orin解决RTC时间问题

因为是离线运行,首要问题是时间不准确,就在主板上加装了纽扣电池,但是会有一系列问题,比如无法将RTC时间回写到系统时间,或者无法将系统时间写到RTC中等等一些列问题。为解决这些问题,一劳永逸的方式&#…

React中常用的hook函数(二)——useReducer和useContext

React中常用的hook函数(一)——useState和useEffect_usestate useeffect-CSDN博客https://blog.csdn.net/Mrs_Lupin/article/details/142905749?sharetypeblogdetail&sharerId142905749&sharereferPC&sharesourceMrs_Lupin&spm1011.2480.3001.8118React中常用…

Java项目实战II基于Java+Spring Boot+MySQL的智能推荐的卫生健康系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 基于Java、…

《Linux系统编程篇》消息队列(Linux 进程间通信(IPC))——基础篇

文章目录 引言消息队列(Message Queue)消息队列的特点消息队列的特性消息队列的操作ipcs -q 拓展ipcrm 拓展注意事项 结论 “山重水复疑无路,柳暗花明又一村。” ——陆游 引言 《Linux系统编程篇》——基础篇首页传送门 想象一下&#xff0…

微服务设计模式 - 重试模式(Retry Pattern)

微服务设计模式 - 重试模式(Retry Pattern) 定义 重试模式(Retry Pattern)是一种微服务中的设计模式,用于在临时性失败(如网络故障或暂时不可用的服务)发生时,自动重新尝试请求&…

『 Linux 』网络传输层 - TCP(二)

文章目录 TCP六个标志位TCP的连接三次握手 四次挥手为什么是三次握手和四次挥手 重传机制 TCP六个标志位 在TCP协议报文的报头中存在一个用于标志TCP报文类型的标志位(不考虑保留标志位),这些标志位以比特位选项的方式存在,即对应标志位为0则表示为假,对应标志位为1则为真; SYN…

VLAN虚拟局域网,eNSP实验讲解

VLAN虚拟局域网,eNSP实验讲解 一、概念二、eNSP仿真实验1、实验一:vlan演示(交换机端口access模式)2、实验二:vlan演示(交换机端口trunk模式) 一、概念 VLAN(Virtual Local Area Ne…

Ubuntu UFW防火墙规则与命令示例大全

在服务器安全领域,防火墙是守护网络安全的坚实盾牌。UFW(Uncomplicated Firewall),即“不复杂的防火墙”,是一个运行在iptables之上的防火墙配置工具,它为Ubuntu系统默认提供了一个简洁的命令行界面&#x…

基于 Python 的 Django 框架开发的电影推荐系统

项目简介:本项目是基于 Python 的 Django 框架开发的电影推荐系统,主要功能包括: 电影信息爬取:获取并更新电影数据。数据展示:提供电影数据的列表展示。推荐系统:基于协同过滤算法实现个性化推荐。用户系…

ORB-SLAM2源码学习:ORBextractor.cc:IC_Angle 利用灰度质心法求解关键点方向角

ORB特征点: 特征点是由关键点和描述子两部分组成,关键点是指特征点在图像中的位置,描述子是用来描述关键点周围的像素信息。ORB关键点是在FAST关键点的基础上进行改进给像素增加了一个主方向,称为Oriented FAST。描述子在BRIEF的…

【设计模式】如何用C++实现依赖倒置

【设计模式】如何用C实现依赖倒置 一、什么是依赖倒置? 依赖倒置原则(Dependency Inversion Principle,DIP)是SOLID面向对象设计原则中的一项。它的核心思想是: 高层模块不应该依赖于低层模块,两者都应该…

‌植物神经紊乱患者,这些锻炼适合你!

植物神经紊乱是一种常见的心理疾病,其主要症状包括焦虑、抑郁、失眠等,严重时还可能出现心慌、气短、憋气、出汗异常等症状。然而,通过适量的锻炼,我们可以帮助调节自主神经系统,缓解这些症状。那么,植物神…

Golang | Leetcode Golang题解之第525题连续数组

题目: 题解: func findMaxLength(nums []int) (maxLength int) {mp : map[int]int{0: -1}counter : 0for i, num : range nums {if num 1 {counter} else {counter--}if prevIndex, has : mp[counter]; has {maxLength max(maxLength, i-prevIndex)} …

第十七届山东省职业院校技能大赛通知分享

近日,山东省教育厅联合相关部门发布了关于举办第十七届山东省职业院校技能大赛的通知,标志着这一旨在深化教育教学改革、推进产教融合与校企合作的重要赛事即将拉开帷幕。 据了解,本次大赛将设中等职业教育组和高等职业教育组,共包…

Angular实现gridview效果

说明&#xff1a;使用angular实现grid效果&#xff0c;支持文字图片多条数据展示 效果图: step1: <mat-grid-list cols"2" rowHeight"2:1"><mat-grid-tile *ngFor"let course of courses">{{ course }}</mat-grid-tile> &l…

web of sicence使用教程(研究生版)

学习视频链接 进入web of science 通过校园资料库进入进入&#xff0c;选择如下 核心检索规则 不区分字母大小写逻辑运算符 可以通过括号改变优先级 常用通配符 短语检索 检索界面 检索类型 选择数据库

2-8软件包管理

8.1 配置仓库 1.配置本地仓库 #进行代码安装前需要先进行仓库配置和挂载 [rootlocalhost ~]# cd /etc/yum.repos.d [rootlocalhost yum.repos.d]# vim base.repo [baseos] namebaseos baseurl/mnt/BaseOS gpgcheck0 [appstream] nameappstream baseurl/mnt/AppStream gp…

适配器模式:类适配器与对象适配器

适配器模式是一种结构性设计模式&#xff0c;旨在将一个接口转换成客户端所期望的另一种接口。它通常用于解决由于接口不兼容而导致的类之间的通信问题。适配器模式主要有两种实现方式&#xff1a;类适配器和对象适配器。下面&#xff0c;我们将详细探讨这两种方式的优缺点及适…