java多线程(并发)夯实之路-synchronized锁升级深入浅出

轻量级锁

使用场景:一个对象有多线程访问,但时间是错开的(如果多线程同时访问,也就是有竞争的,会升级为重量级锁)

轻量级锁对使用者是透明的,语法仍是synchronized

例:

以上的代码运行会先在方法产生的栈帧内创建锁记录(Lock  Record)对象,每个线程的栈帧都会包含一个锁记录的结构。锁记录中有锁对象指针(Object reference)和锁对象Mark Word记录

然后会尝试用cas(CompareAndSwap)替换Object的Mark  Word

如果对象Mark Word最后两位是01,就交换成功,否则会失败

cas失败有两种情况:

其他线程持有该Object的轻量级锁,这表明有竞争,进入锁膨胀过程

自己执行了synchronized锁重入,将再添加一条Lock Record作为重入的计数

第二次加锁,为锁重入,创建一个新的锁记录,里面会存一个null和Object reference,可以根据锁记录条数知道加了多少次锁

解锁时,如果有取值为null的锁记录,表示有重入,将清除值为null的锁记录,表示重入计数减一

最后一次解锁时,将用cas把Mark Word的对象头还原成功,则解锁成功

失败,说明轻量级锁经过锁膨胀变为重量级锁,进入重量级锁解锁流程

锁膨胀

线程为对象加上轻量级锁后,有竞争,这时会进行锁膨胀,轻量级锁变为重量级锁

将为Object对象申请Monitor锁,让Object指向重量级锁地址,后两位变为10
然后自己进入Monitor的EntryList  BLOCKED

当Thread-0退出同步块解锁时,使用cas将Mark  Word的值恢复给对象头会失败,这时进入重量级锁解锁流程,即按照Monitor地址找到Monitor对象,设置Owner为null,唤醒Monitor的EntryList线程

自旋优化

竞争重量级锁时,可以用自旋来优化,线程自旋过程中如果持锁线程退出同步块,释放了锁,线程就自旋成功,线程就避免了阻塞。

自旋成功:

自旋失败:

java6之后自旋是自适应的

自旋会占用CPU时间,多核CPU才能发挥自旋优势(单核CPU自旋只会失败,还浪费了时间)  java7之后不能控制是否开启自旋

偏向锁

轻量级锁重入时仍然需要CAS操作                      

java6中引入偏向锁进行优化:第一次CAS将线程ID设置到对象的Mark Word头,之后发现这个线程ID是自己的就表示没有竞争(锁重入),不用重新CAS,之后只要不发生竞争,锁对象就归该线程所有。

一个对象创建时会开启偏向锁(默认),但偏向锁默认是延迟的(避免延迟可以加VM参数- XX:BiasedLockingStartupDelay=0)。创建后,markword的值为0x05即后三位为101,这时它的 thread,epoch,age都为0;如果没有开启偏向锁,对象创建后,markword值为0x01即后三位为001,这时它的hashcode,age都为0,第一次使用到hashcode时才会赋值。(锁释放后markword后三位为 001)

使用场景:没有竞争

偏向锁有其他线程访问会变为轻量级锁,有竞争(多线程同时访问)会锁膨胀变为重量级锁可以加VM参数-XX:-UseBiasedLocking禁用偏向锁

调用哈希码会禁用偏向锁(因为偏向锁的markword中没空间存哈希码,所以撤销偏向锁,轻量级锁调用哈希码,会存在线程栈帧的锁记录里,重量级锁调用哈希码,会存在Monitor里)

调用wait/notify(升级为重量级锁)会禁用偏向锁

批量重偏向

对象被另一线程访问,偏向锁被撤销变为轻量级锁

没有竞争的情况下,如果一个线程有同类多个偏向锁对象,偏向锁被另一线程访问,偏向锁撤销次数过多,将进入批量重偏向状态,第20次以及之后偏向锁会重新偏向到另一线程(重偏向会重置对象的Thread ID)

批量撤销

偏向锁撤销次数到40,会将整个类的对象设为不可偏向(normal),新建对象也是不可偏向

锁消除

JIT即时编译器优化过程中会进行锁消除

如下不会执行加锁操作

原理之wait/notify

Owner线程发现条件不满足,调用wait方法,线程会释放锁,进入WaitSet变为WAITING状态,然后唤醒BLOCKED状态的线程来竞争,新的Owner线程调用notify/notifyAll方法会唤醒WaitSet中的线程,唤醒后的线程仍需进入EntryList重新竞争

WAITING和BLOCKED都是阻塞状态,不占用CPU时间片

这些都属于object对象的方法,只有取得了对象的锁才能调用这些方法 wait方法无参为一直等待,有参为有时限的等待

与sleep区别:          

1)sleep是Thread方法,wait是Object方法

2)sleep不需要与synchronized配合使用,wait需要

3)sleep不会释放对象锁,wait会

如果它们都是有参的,都是进入TIME_WAITING状态锁对象加final

用while循环可以解决虚假唤醒的问题(等待时间结束,没有满足条件却继续往下执行)

Park&Unpark

它们是LockSuppport类中的方法

与wait/notify相比:

wait/notify需要配合Object Monitor一起使用,而park,unpark不用 notify唤醒是随机的,notifyAll唤醒全部,而unpark可以准确地唤醒线程 park&unpark可以先unpark,wait&notify不能先notify

每个线程都有一个park对象,由三部分组成_counter(值只能为1或0),_cond,_mutex

调用park,会检查counter的值,为0则停止(获得_mutex互斥锁,进入_cond条件变量阻塞),为1则运行。并把counter值设为0

调用unpark,设counter值为1,如果线程停止了,让它继续运行并把_counter设为0(唤醒了_cond条件变量的线程)

总结:

线程为对象加上轻量级锁后,有竞争,这时会进行锁膨胀,轻量级锁变为重量级锁。竞争重量级锁时,可以用自旋来优化,线程自旋过程中如果持锁线程退出同步块,释放了锁,线程就自旋成功,线程就避免了阻塞。偏向锁有其他线程访问会变为轻量级锁,有竞争(多线程同时访问)会锁膨胀变为重量级锁可以加。

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

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

相关文章

天津Java开发培训哪家好?选Java培训班要考虑

在当今社会,Java语言在软件开发领域具有举足轻重的地位,Java是一门面向对象编程语言,Java语言集合了C的优点,丢弃了缺点,所以Java语言表现的功能强大而简单易用,已经得到越来越多的应届毕业生和职场新人的认…

智慧公厕创造智能、整洁、舒适环境,让“方便”更方便

在现代城市建设中,智慧公厕已成为一项热点技术。通过物联感知、云管理数据处理和人性化智能设备的融合,智慧公厕让我们的“方便”变得更加方便。不仅实时感知和监控公共厕所的情况,还提升管理效率,为市民提供更人性化的服务。智慧…

Authing 入选中国信通院《 2023 高质量数字化转型产品及服务全景图》

近日,中国信通院“铸基计划”发布了《高质量数字化转型产品及服务全景图( 2023 )》。Authing 身份云成功入选 IT 维护与运营领域并获得证书。 “十四五”时期,我国数字经济转向深化应用、规范发展、普惠共享的新阶段,数字化转型已成为传统企业…

STM32——电容触摸按键充电时间测量实验

1电容触摸按键 无手指触摸:上电时,电阻作用下,电容Cs进行充电,直到电容充满,这时候会有一个充电时间Tcs。 有手指触摸:上电时,电阻作用下,电容Cs和Cx进行充电,电容充满时…

2719. 统计整数数目

给你两个数字字符串 num1 和 num2 &#xff0c;以及两个整数 max_sum 和 min_sum 。如果一个整数 x 满足以下条件&#xff0c;我们称它是一个好整数&#xff1a; num1 < x < num2min_sum < digit_sum(x) < max_sum. 请你返回好整数的数目。答案可能很大&#xff…

jquery(一)

目录 &#x1f338;基本使用 &#x1f341;两大特性 &#x1f338;操作文档 &#x1f338;样式操作 &#x1f338;属性操作 &#x1f338;文档操作 &#x1f341;内部追加 &#x1f340;原来界面 &#x1f340;追加后界面 &#x1f341;外部追加 &#x1f340;原来界…

进阶Docker2:数据卷和挂载目录

目录 准备 删除容器 创建并运行一个容器 数据卷&#xff08;Volumes&#xff09; 挂载数据卷 虚拟机端口映射 挂载目录&#xff08;Bind mounts&#xff09; 挂载目录 挂载文件 部署在线项目 docker 在容器中管理数据主要有两种方式&#xff1a; - 数据卷&#xff0…

陪诊小程序开发|陪诊软件定制|陪诊系统成品功能包含哪些?

陪诊小程序是一种便捷的工具&#xff0c;为用户提供一系列服务和功能&#xff0c;方便患者在就医过程中获得更好的体验和效果。接下来我们将介绍几个主要的陪诊小程序功能。 陪诊小程序开发功能&#xff1a; 一、预约挂号功能。陪诊小程序能够连接用户和医疗机构的系统&#x…

ART-Adversarial Robustness Toolbox检测AI模型及对抗攻击的工具

一、工具简介 Adversarial Robustness Toolbox 是 IBM 研究团队开源的用于检测模型及对抗攻击的工具箱&#xff0c;为开发人员加强 AI模型被误导的防御性&#xff0c;让 AI 系统变得更加安全&#xff0c;ART支持所有流行的机器学习框架 &#xff08;TensorFlow&#xff0c;Ker…

什么是JAVA的包装类?用了有什么好处?

目录 一、包装类概述 二、包装类和基本数据类型的转换 三、使用包装类的ValueOf方法 四、基本类型和包装类的自动转换 一、包装类概述 Java的包装类是为了方便操作基本数据类型而提供的类。Java的基本数据类型&#xff08;如int、char、boolean等&#xff09;是非对象的&a…

【备战蓝桥杯】——Day1

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-xKn7nmq36s9pgUXR {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

Django教程第4章 | Web开发实战-三种验证码实现

系列&#xff1a;Django学习教程 验证码的存在是为了防止系统被暴力破解攻击&#xff0c;几乎每个系统都有验证码。下面将介绍三种生成验证码方式。 您可以根据你自己的需要进行学习。 手动生成验证码 安装绘图依赖&#xff0c;利用的是画图模块 PIL 以及随机模块 random 在后…

python解决求最短路径、最短时间问题

对于一个求最短路径的经常遇到的问题&#xff0c;对于从某一个节点到其余全部节点所需要的最短时间的问题&#xff0c;可以使用广度优先搜索算法的思路来进行解决&#xff0c;这是一个广度优先搜索算法在二维空间的应用。 问题描述为给定一个节点总数为N和一个列表list&#x…

fastadmin答题考试系统开源二次开发带拍照搜题版本

应用介绍 应用介绍 一款基于FastAdminThinkPHPUniapp开发的小程序答题考试系统&#xff0c;提供全部前后台无加密源代码&#xff0c;支持私有化部署 前端截图&#xff1a; 后台截图&#xff1a; 功能介绍&#xff1a;

LeetCode 每日一题 Day 37-43

终于考完试了&#xff0c;寒假期间将会每天持续更新&#xff01; 447. 回旋镖的数量(Day 37) 给定平面上 n 对 互不相同 的点 points &#xff0c;其中 points[i] [xi, yi] 。回旋镖 是由点 (i, j, k) 表示的元组 &#xff0c;其中 i 和 j 之间的欧式距离和 i 和 k 之间的欧…

颜色对话框 QColorDialog

1. 颜色对话框 QColorDialog 1.1 基本函数 QColor getColor(const QColor &initial Qt::white, QWidget *parent nullptr, const QString &title QString(), QColorDialog::ColorDialogOptions options ColorDialogOptions())返回值&#xff1a;QColor&#xff0c;…

SpringBoot+SSM项目实战 苍穹外卖(11) Apache ECharts

继续上一节的内容&#xff0c;本节学习Apache ECharts&#xff0c;实现营业额统计、用户统计、订单统计和销量排名Top10功能。 数据统计效果图&#xff1a; 目录 Apache ECharts入门案例 营业额统计用户统计订单统计销量排名Top10 Apache ECharts Apache ECharts 是一款基于 …

使用 Clojure 进行 OpenCV 开发简介

从 OpenCV 2.4.4 开始&#xff0c;OpenCV 支持使用与 Android 开发几乎相同的接口进行桌面 Java 开发。 Clojure 是由 Java 虚拟机托管的一种现代 LISP 方言&#xff0c;它提供了与底层 JVM 的完全互操作性。这意味着我们甚至应该能够使用 Clojure REPL&#xff08;Read Eval …

代码随想录 Leetcode1. 两数之和

题目&#xff1a; 代码&#xff08;首刷看解析 2024年1月15日&#xff09;&#xff1a; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {int another 0;unordered_map<int,int> hash;for(int i 0; i < nums.size();…

arcgis javascript api4.x以basetilelayer方式加载天地图web墨卡托(wkid:3857)坐标系

需求&#xff1a; arcgis javascript api4.x以basetilelayer方式加载天地图web墨卡托&#xff08;wkid&#xff1a;3857&#xff09;坐标系 效果图&#xff1a; 代码&#xff1a; 提示&#xff1a; 2个文件放同一个文件夹下 MyCustomTileLayer.js define([exports, "…