Synchronized原理和jdk1.8后的优化

手把手教你在Keil/IAR中移植SEGGER_RTT组件(避坑指南+性能对比) 本文详细介绍了在Keil/IAR开发环境中移植SEGGER RTT调试组件的完整流程与优化技巧。通过对比传统串口调试,SEGGER RTT凭借零硬件占用、高速传输和双向交互等优势,显著提升嵌入式开发效率。文章包含配置步骤、性能调优方案及常见问题解决方案,是嵌入式开发者必备的实用指南。 阅读详情

Synchronized关键字使用较多的形式如下所示:

1:以synchronized同步代码块的形式

synchronized(Object){
    //代码
}

2:对一个方法进行synchronized声明,进而对一个方法进行加锁来实现同步。如下面代码

public synchornized void test(){
    //代码
}

上述中其实都是对对象加锁,对于第二种如果非static方法,当前锁为this对象,若为static方法当前锁为当前类的Class对象。

锁对象

java中任何一个对象都可以称为锁对象,原因在于java对象在内存中存储结构,如下图所示:

图1

在对象头中主要存储的主要是一些运行时的数据,如下所示:

长度内容说明
32/64bitMark WorkhashCode,GC分代年龄,锁信息
32/64bitClass Metadata Address指向对象类型数据的指针
32/64bitArray Length数组的长度(当对象为数组时)

其中 在Mark Work中存储着该对象作为锁时的一些信息,如下所示是Mark Work中在64位系统中详细信息:

图2

从上图可以看出,对于对象锁可能存在的4中状态:无锁->偏向锁->轻量级锁->重量级锁,并且其中锁的升级是不可逆的。

偏向锁

偏向锁和无锁的标志位在Mark Work中的标志位都为01,只不过区别在于是否生效来,这也说明任何一个对象被创建出来,都可能是偏向的,具体是否偏向要看具体实现。从偏向锁的定义上可以看出,该锁的着重点在于偏字上,它会偏向与第一个获取它的线程,这句话什么意思呢?当一个线程进入到被Synchronized修饰的代码时(官方话叫临界区时-只允许一个线程进去执行操作的区域),就根据CAS(Compare and Swap)的操作将线程的id插入到Mark Work中指定区域(上图中54bit区域),并且将当前偏向锁状态改为1(上述的操作实际上就是一个偏向锁上锁的过程)。那么代表当前线程已经获取执行同步代码块的权利了。当后续该线程进来时,如果该锁没有被其他锁获取到或者没发生锁竞争,那么就会再有任何的同步措施,即加锁或者解锁的措施了,只会进行Load-and-test,也就是简单判断一下当前线程id是否与Markword当中的线程id是否一致。

如果当前偏向锁出现了锁竞争的话,当前线程也会判断之前拥有锁的线程是否存在或者存在但没拥有该锁状态,就进行重置该偏向锁,并重新进行上锁过程,若仍然存在,此时该偏向锁就会升级为轻量级锁。在这个升级的过程中就会涉及到锁撤销的过程,锁撤销的过程也是满复杂的,资源的消耗也挺大的。所以如果我们的应用中大量都是存在多线程锁竞争的关系,那么不断的进行锁升级,其实是一个没必要的事情,此时我们可以在启动的时候设置-XX:-UseBiasedLocking = false,即该应用就不存在偏向锁了。

轻量级锁

当一个锁从偏向锁升级为轻量级锁时,那么对应的Mark Work中的数据格式也会发生变更,如图二所示:

  1. 锁的标志位切换为00
  2. 在当前线程栈创建锁记录LockRecord
  3. 将锁对象的对象头中的MarkWord复制到线程的刚刚创建的锁记录中
  4. 将锁记录中的Owner指针指向锁对象
  5. 将Mark Work中62bit的空间存储指向获取锁线程的锁记录LockRecord

如下图所示:

  

 轻量级锁有两种:自旋锁和自适宜自旋锁

自旋锁:

顾名思义当出现线程锁竞争的时候,已经获取锁资源的线程执行同步代码块中代码,没有获取到的线程不会挂起而是在原地循环等待,而不是把该线程给阻塞,直到那个获得锁的线程释放锁之后,这些等待的线程就会进行下一次的锁竞争。在线程自旋的过程中这些线程是存活的,只不过cpu是一直空转的,就是相对于执行一个没有结束的for循环(在java源码中有关于CAS的操作大都是通过for进行自旋)。如果说自旋次数过多就会导致cpu资源的浪费,所以对于自旋的次数,java对其做了规定,默认每个线程最多执行10次(该值)。所以从这上面看来如果要求自旋锁能达到最优状态,最好是同步代码块中的代码执行时间短,并且只存在少量的锁竞争关系。

自适宜自旋锁:

该锁在jdk1.6的时候被引入,线程的自旋次数不再是固定值了而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也是很有可能再次成功,进而它将允许自旋等待持续相对更长的时间。如果对于某个锁,自旋很少成功获得过,为了避免浪费处理器资源,那在以后尝试获取这个锁时将可能省略掉自旋过程,直接升级为重量级锁

重量级锁

对包含Synchronized的代码进行反编译之后会发现在同步块的前后分别形成monitorenter和monitorexit这两个字节码指令。

关于这两条指令的作用,我们直接参考JVM规范中描述:

monitorenter :

每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

1、如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。

2、如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.

3.如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

monitorexit: 

执行monitorexit的线程必须是objectref所对应的monitor的所有者。

指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权。

通过这两段描述,我们应该能很清楚的看出Synchronized的实现原理,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

从上面对于monitorenter与monitorexit的描述也可以看出Synchronized是一个重入锁,每次重入对应的monitor的进入数+1,退出减1.

Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的,而操作系统实现线程之间的切换这就需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么Synchronized效率低的原因。因此,这种依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。在JDK1.6之前,Synchronized主要就是依赖与重量级锁实现各个功能,所以1.6之前建议不要使用Synchronized而使用ReentrantLock锁,在JDK1.6之后为了减少获得锁和释放锁所带来的性能消耗,提高性能,引入了“轻量级锁”和“偏向锁”,最终使得Synchronized的效率与ReentrantLock相差无几,甚至在某些场景下还优胜与ReentrantLock。 

参考:周志明老师的<深入理解Java虚拟机>

【雕爷学编程】Arduino FOC 之 AS5600 磁编码器的模拟电压与IIC通信 在Arduino平台上实现FOC可以提供平滑的运行和高度的扭矩、速度和位置控制,它通过精确控制电机的电流和电压来实现高效率、高精度和低噪声的操作。案例三在使用I2C通信读取角度值的基础上,添加了设置角度范围的功能。5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。1、高性能电机控制:FOC是一种高级的电机控制算法,可以精准控制PMSM(永磁同步电机)和BLDC(无刷直流)电机,实现平滑的转速和扭矩输出。 阅读详情

相关推荐

从DBC到ARXML:详解DaVinci Configurator中通信栈的自动化配置逻辑

本文深入解析了Vector公司DaVinci Configurator工具如何将DBC文件自动转换为符合AUTOSAR标准的ARXML配置,详细介绍了从DBC到ARXML的映射逻辑、自动化配置的边界与陷阱,以及工程实践中的优化策略。帮助工程师高效配置汽车电子系统中的通信协议,提升项目开发效率。

weixin_30279671的博客 717

Java Synchronized

synchronized

Monkey_4 882

LLC电路细讲笔记(二)LLC谐振转换器:频率、增益与Q值的详细探讨

这本电子书通过详细分析LLC谐振转换器的工作原理、等效电路和增益公式,帮助读者深入理解如何设计和优化谐振转换器系统。通过这些公式和设计方法,工程师可以根据不同的应用需求调整参数,实现高效的电能转换。

weixin_43199439的博客 6881

jdk1.8对synchronized锁的优化

synchronized 锁的优化:锁的四种状态-无锁,偏向锁、轻量级锁,重量级锁 1、偏向锁:原因是大多数时候是不存在锁竞争的,常常是一个线程多次获得同一个锁,因此如果每次都要竞争锁会增大很多没有必要付出的代价,为了降低获取锁的代价,才引入的偏向锁 偏向锁的升级:当线程1访问代码块并获取锁对象时,会在java对象头和栈帧中记录偏向的锁的threadID,因为偏向锁不会主动释放锁,以后线程1再次获取锁时比较当前线程的threadID和Java对象头中的threadID是否一致,如果一致(还是线程1获

常敲代码手不生 4783

YOLO26涨点改进| CVPR 2026 | 独家创新首发、特征融合改进篇 | 引入 LFSB 差分双维注意融合模块,通过交替特征融合与分离策略,能够精准区分目标特征,顶会助力YOLO26有效涨点

本文提出LSFB差分双维注意融合模块,用于改进YOLO26目标检测模型。该模块通过融合-分离交替策略和差分注意力机制,有效提升模型在复杂场景下的特征分离能力,特别是在处理重叠物体或反射干扰时表现优异。LSFB采用双向投影、双维注意力计算和跨流减法算子,实现特征共享与独立提取的平衡。实验表明,该模块能显著减少特征混淆,提高检测精度和鲁棒性。文章还详细介绍了模块实现的核心代码、YAML配置文件修改方法以及三种改进方案,为YOLO26模型性能提升提供了创新解决方案。

Ai缝合怪、助力小伙伴高效发论文 326

LeRobot 官方论文:一个用于端到端机器人学习的开源库

本文介绍了一个名为LeRobot的开源库,旨在解决机器人学习领域的碎片化问题。该库提供了端到端的技术栈,包括统一的机器人中间件API、标准化的数据集格式(LeRobotDataset)、优化的推理栈以及多种最先进机器人学习算法的实现。LeRobot支持多种低成本开源机器人平台(如SO-10X、ALOHA-2等),通过共享中间件实现便捷的遥操作和数据收集。其数据集格式已广泛应用于社区,截至2025年9月已有16,000多个数据集公开共享。该库还支持流式处理大规模数据,降低了研究门槛。在模型方面,LeRobot

2506_90492529的博客 905

synchronized的优化机制和一些多线程的常见类

synchronized 是一个自适应的锁 是乐观锁也是悲观锁 不是读写锁,是普通互斥锁 是轻量级锁,也是重量级锁 轻量级锁基于自旋的方式实现,重量级锁基于挂起等待实现 是非公平锁 是可重入锁

m0_58154870的博客 1145

MCAL中MCU的配置

MCAL配置中MCU配置,PLL计算配置,系统时钟以及各模块参数配置

dhyw12399999的博客 3794

再有人说synchronized是重量级锁,就把这篇文章扔给他看

synchronized锁经过多次迭代优化,已经不像以前那么重了,在JDK1.8的ConcurrentHashMap源码中已经大量使用synchronized做同步控制,大家在日常开发中可以放心使用了。

chuixue24的博客 196

[RK3568 Android11] 开发之默认授予系统预置的APP权限

目录 一、系统预置的APP权限 二、默认授予系统预置的APP权限 一、系统预置的APP权限 1、在打开系统预置的APP时,都会弹窗提示,并且需要人工确定授予权限; 2、有些客户对定制有需求,需要系统预置的APP自动默认授予权限; 二、默认授予系统预置的APP权限 注意此方法只对系统预置的APP起效果,后期手动安装的APP无效; 修改文件: frameworks/base/services/core/java/com/android/server/pm/per...

~未来可期~ 5059

李宏毅2025《机器学习》第一讲-生成式AI:技术突破和未来发展

本文基于台湾大学李宏毅教授的“一堂课搞懂生成式人工智慧的技术突破与未来发展”课程内容,系统性地梳理了生成式AI的核心概念、技术原理、发展演进以及未来趋势。文章从AI的“行为”入手,通过生动的实例展示了其强大的生成与推理能力;进而深入剖析其底层运作机制,阐释了“万物皆为令牌(Token)”、自回归生成、Transformer架构等核心原理;接着,文章追溯了通用AI模型从“专才”到“通才”的演进历程;最后,探讨了如何通过微调(Fine-tuning)、模型编辑(Model Editing)等技术赋予AI新的能力

木鱼时刻的专栏 2295

Java多线程~synchronized原理以及优化

synchronized的基本特点、实现原理(monitor机制)、JVM对于synchronized的优化“锁升级”:无锁、偏向锁、轻量级锁、重量级锁;synchronized的其他的优化,锁消除与锁粗化

qq_58284486的博客 673

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

科普文: jdk 1.7和 jdk 1.8 中ConcurrentHashMap 原理浅析

如果 f.hash >= 0,说明 f 是链表结构的头结点,遍历链表,如果找到对应的 node 节点,则修改 value,否则在链表尾部加入节点。JDK1.8 的实现已经摒弃了 Segment 的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 Synchronized 和 CAS 来操作,整个看起来就像是优化过且线程安全的 HashMap,虽然在 JDK1.8 中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本。采取分段锁来保证安全性。

为无为,事无事,味无味。 1061

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

ConcurrentHashMap实现原理(含JDK1.7和JDK1.8对比)

ConcurrentHashMap的前世今生 1 JDK1.7下的ConcurrentHashMap 在JDK1.7之前的ConcurrentHashMap采用的是分段锁的思想,支持并发操作,所以是线程安全的。ConcurrentHashMap在内部划分成了若干个数据段(Segment),可以把每一段都大致理解成是一个HashMap。默认Segment大小为16,Segment的个数也就是锁的并...

Blog of Jatsby 319

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

ConcurrentHashMap在jdk1.7和jdk1.8中的不同(简单说)

原博客:https://www.cnblogs.com/lujiango/p/7580558.htmlhttp://www.importnew.com/28263.html CouncurrentHashMap 线程安全 一、CouncurrentHashMap<jdk1.7>底层: 1.底层数据结构 <jdk1.7>:数组(Segment) + 数组(HashEn...

HD243608836的博客 1277

ConcurrentHashMap原理分析(JDK1.7与1.8)

前言 前面写过介绍HashMap的文章(https://blog.csdn.net/qq_27574367/article/details/88526194 ),文中提到过HashMap在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原数组的内容重新hash到新的扩容数组中,在多线程的环境下,存在同时其他的元素也在进行put操作,如果ha...

欢迎光临 370

ConcurrentHashMap底层实现原理(JDK1.7 & 1.8)

ConcurrentHashMap底层实现原理(JDK1.7 & 1.8) 前言 我们都知道HashMap在多线程情况下,在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原数组的内容重新hash到新的扩容数组中,在多线程的环境下,存在同时其他的元素也在进行put操作,如果hash值相同,可能出现同时在同一数组下用链表表示,造成闭环,导致在get时会出现死循环,所以HashMap是线程不安全的。 我们来了解另一个键值存储集合HashTable

jiohfgj的博客 604

ConcurrentHashMap的实现原理(JDK1.7和JDK1.8)

高并发编程系列:ConcurrentHashMap的实现原理(JDK1.7和JDK1.8) 哈希表 1.介绍 哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。 哈希的思路很简单,如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速访问任意键的值。这是对于简单的键的情况,...

WuJun_025的博客 377

ConcurrentHashMap原理分析(1.7 1.8)

1.8中使用一个volatile类型的变量baseCount记录元素的个数,当插入新数据或则删除数据时,会通过addCount()方法更新baseCount,实现如下: 1、初始化时counterCells为空,在并发量很高时,如果存在两个线程同时执行CAS修改baseCount值,则失败的线程会继续执行方法体中的逻辑,使用CounterCell记录元素个数的变化; 2、如果CounterC...

lucky_C的博客 404

JDK1.7的ConcurrentHashMap 的put、get、remove工作原理

很详细,很不错,好理解 https://www.cnblogs.com/heqiyoujing/p/10928423.html

weixin_44683593的博客 1238

ConcurrentHashMap 全体系深度解析(JDK 1.7 → JDK 1.8 全面对比)

摘要:ConcurrentHashMap 是 Java 并发编程的核心容器,解决了 HashMap 线程不安全与 Hashtable 性能差的问题。JDK1.8 采用 CAS + synchronized + 红黑树实现,通过分段锁(桶级锁)、volatile 变量和多线程协作扩容机制,兼顾线程安全与高性能。关键特性包括:put 操作空桶用 CAS、非空桶用 synchronized,链表长度≥8且容量≥64时树化,get 全程无锁,禁止 null 值。其设计演进(从 JDK1.7 分段锁到 1.8 细粒度

写代码写久了才发现:人生和程序一样,经常 Bug 多、需求乱,重构难,但总能跑起来。这个博客记录我从迷茫到搞懂、从踩坑到归纳、从混乱到清晰的过程。写给过去迷茫的自己,也写给同样在路上折腾的你。没有炫技,没有玄学,只有真实的思考、实践和成长。 801

Java集合:ConcurrentHashMap(JDK 1.7 & JDK 1.8)

ConcurrentHashMap(JDK 1.7) HashTable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,...

五山口老法师 732

ConcurrentHashMap实现原理以及源码解析(jdk1.8)

ConcurrentHashMap实现原理以及源码解析(jdk1.8) 参考资料: https://blog.csdn.net/xu768840497/article/details/79194701 http://www.cnblogs.com/leesf456/p/5453341.html https://www.cnblogs.com/banjinbaijiu/p/9147434.html 一、数据结构 1.1、先看一下1.7中的底层数据结构 <jdk1.7>:数组(S.

Eric的博客 1499

currenthashmap扩容原理_一篇搞定基于JDK1.7,JDK1.8 HashMap、ConcurrentHashMap原理分析

一、开篇HashMap、CurrentHashMap 面试时都要问烂了,用也用烂了。但是网上的解析要不就是不够全面,要么就是copy来copy去,连基于JDK版本有的都很混乱。这篇文章带你解析 基于jdk1.7、jdk1.8不同的hashMap和ConcurrentHashMap简略分析(很多代码和HashMap都是重复的)。希望看完后有所收获。二、提出问题1、我们都知道,HashMap是线程不安...

weixin_39786155的博客 790

Java 深入理解 ConcurrentHashMap (数据结构、实现原理、JDK版本区别,读写相关锁)

问题: JDK1.7和JDK1.8的ConcurrentHashMap底层数据结构有何区别? JDK1.7和JDK1.8的ConcurrentHashMap实现原理有何区别? HashMap、ConcurrentHashMap主要有何区别? ConcurrentHashMap初始大小、加载因子分别是多少? ConcurrentHashMap的put方法的主要流程? 在JDK1.8中ConcurrentHashMap,为何要用synchronized代替ReentrantLock? ConcurrentHa

深海流浪汉 471

ConcurrentHashMap 的优化与工作原理

只有在访问同一个 Segment 时才会加锁,从而降低锁的粒度,提高性能。,多个线程可以同时访问不同的 Segment,提高并发能力。:在插入元素时,先尝试用 CAS 方式写入数据,避免加锁。标记迁移状态,多个线程共同完成数据迁移,避免死锁。的优化,可以重点讲解 JDK 1.8 版本的。采用了不同的优化方案,我们将分别进行讲解。在 JDK 1.7 和 JDK 1.8,:如果链表长度 > 8,转换为红黑树。:如果桶已存在数据,则遍历链表插入。结构复杂,锁粒度仍然较大,进行标记,避免重复扩容。

x² 1420
上一篇: 算法数据结构-树(1)
下一篇: Mysql数据数据库引擎InnoDB与MyISAM
F_Hello_World
博客等级 码龄11年 38粉丝 58原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值