【并发编程学习篇】synchronized的原理

并发编程-synchronized解决原子性问题 当多个线程并发访问某个Java对象(Object)时,无论系统如何调度这些线程,也不论这些线程如何交替操作,这个对象都能表现出一致的、正确的行为,那么对这个对象的操作是线程安全的。如果这个对象表现出不一致的、错误的行为,那么对这个对象的操作不是线程安全的,发生了线程的安全问题。//示例1@Override// 同步代码块形式——锁为this,两个线程使用的锁是一样的,线程1必须要等到线程0释放了该锁后,才能执行。 阅读详情

一、Synchronized 原理是什么

  1. 在jdk1.6之前synchronized重量级锁,基于Monitor(管程是指管理共享变量以及对共享变量操作的过程,让它们支持并发)机制实现,依赖底层操作系统的Mutex Lock互斥锁实现的

  2. 由于权限隔离的关系,应用程序去调用系统方法的时候需要切换到内核状态去执行,这样就涉及到了用户态到内核态的切换,这个切换对性能有较大的影响

  3. 所以在jdk1.6之后呢,synchronized增加了锁升级的机制来平衡数据安全性和性能。synchronized会根据线程竞争的情况,先去尝试在不加重量级锁的情况下去保证线程的安全性,所以引入了偏向锁和轻量级锁的机制

Synchronized 是由 JVM 实现的一种实现互斥同步的一种方式,如果你查看被 Synchronized 修饰过的程序块编译后的字节码,会发现,被 Synchronized 修饰过的程序块,在编译前后被编译器生成了 monitorenter 和 monitorexit 两个字节码指令。

这两个指令是什么意思呢?

  1. 在虚拟机执行到 monitorenter 指令时,首先要尝试获取对象的锁: 如果这个对象没有锁定,或者当前线程已经拥有了这个对象的锁,把锁的计数器 +1;当执行 monitorexit 指令时将锁计数器 -1;
  2. 当计数器为 0 时,锁就被释放了。 如果获取对象失败了,那当前线程就要阻塞等待,直到对象锁被另外一个线程释放为止。

锁的状态是如何记录的?

在 对象头 的 Mark Work 有 2bit 来记录锁的状态标位,由于无锁和偏向锁的锁标识都是 01,没办法区分,这里引入 1bit 的偏向锁标识位来记录是否偏向锁

二、偏向锁原理,为什么引入偏向锁

  1. 大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,如果每次都要竞争锁会增大很多没有必要付出的代价,为了降低获取锁的代价,才引入的偏向锁。
  2. 对于没有锁竞争的场合,偏向锁有很好的优化效果。

2.1 偏向锁如何获取的?

  1. 在偏向锁状态的时候,对象头的 Mark Word 中记录了当前偏向的 Thread Id
  2. 首先会先获取 Mark Word 中记录的偏向的Thread Id,判断当前对象是否处于可偏向状态(即当前没有对象获得偏向锁)。
  3. 如果是可偏向状态,则通过 CAS 操作,把当前线程的ID,写入到 Mark Word 如果成功,表示获得偏向锁成功
  4. 如果CAS失败则说明当前有其他线程获得了偏向锁,这时候就需要将已获得偏向锁的线程执行 偏向锁撤销,并升级为轻量级锁
  5. 偏向锁的撤销需要修改 Mark Word 中的锁状态标志位为无锁,并且需要等待全局安全点,即在这个时间点上没有正在执行的字节码(有性能问题)。

当多个线程争夺一个资源时,JVM 会尝试用偏向锁来提高效率。偏向锁的原理是:当一个线程获得锁时,它将会“偏向”到该线程,并在后续竞争时,会优先分配给这个线程,从而避免线程竞争,但如果某个线程竞争竞争到了锁,而该线程未被偏向,则 JVM 会撤销该锁,并重新分配锁,这会导致性能下降。

三、轻量级锁的获取锁过程

  1. 首先会判断当前是否为无锁状态,也就是Mark Work中是否偏向的标志位为0

  2. 如果是的话开始加锁操作,加锁的的过程首先是将Mark Word 拷贝一份到线程栈,紧接着利用CAS操作尝试更新Mark Word 中指向栈中锁记录的指针的指向

  3. 如果更新成功,则表示成功获取锁,否则直接开始执行锁膨胀(这里轻量级锁没有自旋的操作)

四、重量级锁获取锁的过程

  1. 在重量级的获取的时候会使用 CAS自旋 的方式获取锁,直到自旋到一定的次数以后开始执行入队操作(_crq队列),入队成功后也会再次尝试是否能够获取锁
  2. 如果获取失败,才真正的将线程 挂起,这个反复的CAS自旋的方式去尝试获取锁是为了尽可能的减少 用户态 到 内核态 的操作

五、锁粗化

  1. 假设一系列的连续操作都会对同一个对象反复加锁及解锁,甚至加锁操作是出现在循环体中的,即使没有出现线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。
  2. 如果JVM检测到有一连串零碎的操作都是对同一对象的加锁,将会 扩大加锁同步的范围(即锁粗化)到整个操作序列的外部。
StringBuffer buffer = new StringBuffer();
/**
 * 锁粗化
 */
public void append(){
    buffer.append("aaa").append(" bbb").append(" ccc");
}
  1. 上述代码每次调用 buffer.append 方法都需要加锁和解锁,如果JVM检测到有一连串的对同一个对象加锁和解锁的操作,就会将其合并成一次范围更大的加锁和解锁操作
  2. 即在第一次append方法时进行加锁,最后一次append方法结束后进行解锁

六、锁消除

锁消除即删除不必要的加锁操作。锁消除是Java虚拟机在JIT编译期间,通过 逃逸分析,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间。

逃逸分析(Escape Analysis)

  1. 逃逸分析,是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。
  2. 通过逃逸分析,Java Hotspot编译器能够分析出一个新的 对象的引用的使用范围 从而决定是否要将这个对象分配到堆上。逃逸分析的基本行为就是分析对象动态 作用域。

方法逃逸(对象逃出当前方法)

当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中。

线程逃逸((对象逃出当前线程)

这个对象甚至可能被其它线程访问到,例如赋值给类变量或可以在其它线程中访问的实例变量。

使用逃逸分析,编译器可以对代码做如下优化:

  1. 锁粗化或锁消除:如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。

  2. 将堆分配转化为栈分配:如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配。

  3. 分离对象或标量替换:有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。

jdk6才开始引入该技术,jdk7开始默认开启逃逸分析。在Java代码运行时,可以通过JVM参数指定是否开启逃逸分析:

-XX:+DoEscapeAnalysis  //表示开启逃逸分析 (jdk1.8默认开启)
-XX:-DoEscapeAnalysis //表示关闭逃逸分析。 
-XX:+EliminateAllocations //开启标量替换(默认打开) 
并发编程系列之Synchronized实现原理 并发编程系列之Synchronized实现原理。偏向锁:当一个线程获取到锁后,这把锁就是偏向锁,偏向锁是在锁对象的对象头中记录一个线程id,然后该线程再次获取锁时,直接获取就可以 轻量级锁:如果有第二个线程来竞争锁,这时就会升级为轻量级锁,轻量级锁是不会阻塞线程的,其底层是通过自旋实现的。自旋是通过CAS获取一个预期的标识,如果没获取到,就会一直循环获取,获取到标识,也就标识获取到锁 重量级锁:如果轻量级锁一直自旋也获取不到锁,才会升级为重量级锁,重量锁是会阻塞线程的,也称之为重锁 阅读详情

相关推荐

yolov5 部署jetson nano(通用) 保姆级教学

Jetson nano从配置环境到yolov5成功推理检测全过程 文章目录Jetson nano从配置环境到yolov5成功推理检测全过程一、烧录镜像二、配置环境并成功推理1.更新系统和包2、配置环境2.1 配置CUDA2.2 修改Nano板的显存1.打开终端输入:2.修改nvzramconfig.sh文件:3.重启:4.终端输入:3、安装archiconda(也就是jetson nano板上的anaconda)1.下载地址:2.安装:3.测试conda:4.创建运行yolov5的虚拟环境:5.在conda

weixin_44312422的博客 3万+

Synchronized实现原理及锁优化,具体是jdk哪个版本做了什么优化?

1、Synchronized实现原理依赖于锁机制和内存屏障 从线程安全的三个特性分别对应做了如下的实现: 原子性:锁,其中涉及 锁优化(锁升级(偏向锁、轻量级锁、重量级锁(objectMonitor))、锁粗化、锁消除) 可见性:加了load屏障和store屏障,释放锁flush数据,加锁会refresh数据 有序性:acquire屏障和release屏障,同步代码块内的指令可能重排,但同步代码块内的指令和外面的指令是不会重排的 2、synchronized用的锁是存在Java对象头里的(图可不

m0_37840000的博客 737

DSSAT模型实战:从基础配置到气候情景模拟

本文详细介绍了DSSAT模型在农业模拟中的应用,从基础配置到气候情景模拟的全流程实战指南。通过土壤-植物-大气连续体的动态关系建模,DSSAT能精准预测作物产量,误差率低至8%。文章涵盖气象数据处理、土壤参数配置、管理措施调控等核心技巧,并提供了Python脚本和可视化方法,助力农业科研与决策。

weixin_29264201的博客 1013

synchronized 实现原理

synchronized

我的精神家园 1455

STK新手必看:用700km轨道卫星,5步搞定对地覆盖分析报告

本文为STK新手提供700km轨道卫星对地覆盖分析的5步实操指南,涵盖卫星创建、传感器配置、区域定义、计算设置及报告生成全流程,特别标注常见操作误区与优化技巧,帮助用户快速掌握STK覆盖性分析核心方法。

weixin_42546392的博客 375

华为OD机考真题 新系统 - 小菊的寻宝之旅(Java/Py/C/C++/Js/Go)

华为OD机试真题 新系统【小菊的寻宝之旅】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题 【小菊的寻宝之旅】多语言题解。

qq_45776114的博客 618

肝到头秃!百度强推并发编程笔记我爱了,原来这才叫并发

当这些错误出现时,通常是在最糟糕的时刻,例如在正式产品中,或者在高负载的情况下,当并发性错误被发现时,情况总是比较紧急甚至可以打倒整个项目团队,毁掉整个项目。添加图片注释,不超过 140 字(可选)添加图片注释,不超过 140 字(可选)添加图片注释,不超过 140 字(可选)添加图片注释,不超过 140 字(可选)添加图片注释,不超过 140 字(可选)添加图片注释,不超过 140 字(可选)添加图片注释,不超过 140 字(可选)添加图片注释,不超过 140 字(可选)

m0_63437643的博客 82

机器人控制仿真软件:MATLAB Simulink Control System Toolbox_(1).MATLAB基础知识

MATLAB(Matrix Laboratory)是由MathWorks公司开发的一种高性能数值计算和可视化软件。它广泛应用于科学计算、工程设计、信号处理、控制系统设计、图像处理等领域。强大的矩阵运算能力:MATLAB的核心是矩阵运算,能够高效处理大规模的数值数据。丰富的工具箱:MATLAB提供了大量的工具箱,如Control System Toolbox、Simulink、Signal Processing Toolbox等,这些工具箱覆盖了多个应用领域。易于使用的图形界面。

kkchenjj的博客 904

Java多线程和并发编程实践的学习心得----基础篇3

Java多线程和并发编程实践的学习心得----基础篇3

SunnyAndroider专栏 1286

企业如何开展BI建设--指标体系建设

很多企业的数字化转型工作都是从做BI项目开始的,很多企业认为,BI就是做指标大屏,所以做了很多的驾驶舱,也做了很多指标,有从系统取的,有手工填报的,甚至手工填报的比例占到了70%,最终BI沦为了填报系统,业务认为BI就是把从线下的微信沟通转到了线上录入展示,并没有给业务代来任何提升,久而久之,BI大屏就没人关心,公司高层也认为数据都是填报的,都经过了加工处理,这种数据不可信,不能反映业务开展的实际。其实在BI系统建设之前,我们首先要做的就是要梳理企业的指标,到底我们要展示哪些指标?

263

SAP FICO 金税系统-金税->SAP接口功能开发说明书(接口字段)

SAP FICO 金税系统-金税->SAP接口功能开发说明书(接口字段)

我好像病了的博客 1258

看完全都会了!java用栈实现计算器

线程 线程的启动 实现Runnab1e接口 继承Thread类 实现Callable接口 线程的状态 线程的方法 线程的优先级 守护线程 未捕获异常处理器 并发编程的问题 线程引入开销:上下文切换与内存同步 线程安全性(原子性+可见性) 死锁 线程间通信/线程同步 工具使用 synchronized Lock volatile Atomic Lock使用 深入 可重入锁 ReentrantLock Condition与wait&notify区别 await&signal

m0_57700125的博客 258

ProcessingJoy —— 最简单的实时流体模拟【JAVA】

实现基于非常非常经典的 Paper ——Jos Stam 的Real-Time Fluid Dynamics for Games 代码和注释 float visc = 0.0f; float diff = 0.0f; int N = 250; int size = (N + 2) * (N + 2); float[] u = new float[size]; // 速度, 水平/竖直 float[] v = new float[size]; float[] u_prev = new fl...

ShaderJoy 的兴趣技术杂货铺 2815

Synchronized底层核心原理

本篇文章是关于并发编程中Synchronized锁的底层核心原理知识记录,由于篇幅原因,下篇文章将介绍各种锁的优化原理。

小威的博客 8693

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Java 并发编程上篇 -(Synchronized 原理、LockSupport 原理、ReentrantLock 原理)

一、基本概念 1、进程与线程 进程 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的。 当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。 进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器 等),也有的程序只能启动一个实例进程(例如网易云音乐、360 安全卫士等) 线程 一个进程之内可以分为一到多个线程

雾里 2万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

最经典的 Java 面试真题 100 道:Java+Redis+ 数据库 + 解决方案 + 分布式..

给大家整理了今年来最经典的面试真题 100 道,每个题目都有详细的解答,收集了 java 基础、RabbitMQ,微服务、MySQL 数据库、Java 并发、JVM,Redis、设计模式,Spring / Spring MVC,等专题的经典面试真题,和详细分析。 数据库篇 事务四大特性(ACID)原子性、一致性、隔离性、持久性? 事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL 默认是哪个级别? MySQL 常见的三种存储引擎(InnoDB、MyISAM、MEMORY

kxkxyzyz的博客 102

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Java 并发编程深度解析:synchronized 关键字的内部原理与应用

synchronized 锁的底层原理

码上一元 1546

学习并发编程中的 synchronized

学习并发编程时,synchronized 关键字至关重要。它用于确保同一时间只有一个线程能访问被其修饰的方法或代码块,避免数据不一致。虽然synchronized简化了线程同步,但不当使用会导致性能瓶颈。因此,合理设计锁机制是并发编程的关键。

天天的博客 980

Synchronized 关键字原理

众所周知synchronized关键字是解决并发问题常用解决方案,有以下四种使用方式: 修饰代码块,即同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象。 修饰方法,即同步方法,其作用的范围是整个方法,作用的对象是调...

钱立清的博客 6万+

深入学习并发编程中的synchronized

第一章 并发编程中的三个问题 1.1 可见性 1.1.1 目标 学习什么是可见性问题 1.1.2 可见性概念 可见性(Visibility):是指当一个线程对共享变量进行修改,另一个线程要立即得到修改后的最新值。 1.1.3 案例演示 /* 目标:演示可见性问题 1.创建一个共享变量 2.创建一条线程不断读取共享变量 3.创建一条线程修改共享变量 */ public class Test01Visibility { private stati

Twilight___的博客 443

并发编程系列——wait原理的讨论(1)

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar

java_lyvee的专栏 9318

并发编程 ~ synchronized。

并发编程 ~ synchronized。

lyfGeek的博客 2282

并发编程synchronized实现原理

深入学习并发编程中的synchronized 第一章:并发编程中的三个问题 1.1 可见性 是什么? 一个线程对共享变量进行修改,另一个线程立即得到修改后的新值。 private static boolean flag = true; @Test public void testSynthonized() throws InterruptedException { new Thread(()->{ while (flag){ } }).s

liumangtutu2919的博客 393

Java并发编程 | Synchronized原理与使用

虽然可以按照不同维度来划分 Synchronized 但本身机制是一样的,无论是 Synchronized 函数/代码块,都是通过对象监视器( Monitor )来实现。无论是this、class、object本质上都是一个对象,区别无非代表的是当前实例、类、一般实例,它们都有着对象监视器( Monitor )。Synchronized 的作用范围,依据锁定的对象(object、this、class)、使用方式,可以分成五种情况。同一个线程可以多次进入被锁定的相同对象监视器( Monitor ),

虚幻私塾 1727

并发编程-04synchronized原理

本篇文章主要介绍java同步锁synchronized关键字的使用、底层原理、以及jvm对synchronized关键字的相关优化

落雪 974
上一篇: 【并发编程学习篇】深入理解Java线程
下一篇: 【并发编程学习篇】并发线程池底层原理详解与源码分析
柯十一
博客等级 码龄8年 1715粉丝 53原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柯十一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值