Synchronized原理和jdk1.8后的优化

Hi3516CV610开发板实战:从零搭建智能视觉监控系统 本文详细介绍了从零开始基于Hi3516CV610开发板搭建智能视觉监控系统的完整实战流程。涵盖硬件连接、系统配置、摄像头集成、网络设置、固件烧录到视频处理与智能分析功能开发,提供了丰富的实践经验和调试技巧,帮助开发者快速掌握嵌入式视觉系统开发。 阅读详情

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虚拟机>

MATLAB App Designer 实现多窗口交互与数据传递实战 本文详细介绍了如何使用MATLAB App Designer实现多窗口交互与数据传递的实战技巧。从基础的多窗口应用设计到高级的动态窗口创建,涵盖了窗口调用控制、数据传递方法、状态管理及用户体验优化等核心内容,帮助开发者高效构建复杂的MATLAB GUI应用。 阅读详情

相关推荐

系统动力学仿真软件Vensim下载

Vensim是由美国Ventana Systems, Inc.所开发,是采用图示化编程的方式构建系统动力学模型,上手简单。Vensim有很多系列产品,其中Vensim PLE (Personal Learning Edition)是面向个人学习者的,完全免费,可直接官网下载,截止于2022/04/10,最新的Vensim PLE版本是9.2.3。

PMIIᶜᶜ的博客 1万+

Java Synchronized

synchronized

Monkey_4 882

文华指标源码—区间彩带

这就是当年东方财富软件终端里主打经典的指标、主要揭示主力成本区域。

qq2054129753的博客 888

jdk1.8对synchronized锁的优化

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

常敲代码手不生 4783

防火墙断网后Adobe软件还弹窗“THIS APP HAS BEEN DISABLED”?原来是科学上网导致的问题!用这个简单方法一键解决!

很多小伙伴在使用上网工具的时候时,突然遇到Adobe弹出“THIS APP HAS BEEN DISABLED”的烦人提示,这个非正版弹窗真的让人头疼!即使你之前尝试过,有时也不奏效,究其原因,原来是因为你使用了代理网络,这时Adobe的流量并不是走本地,而是走代理,导致防火墙的拦截无效。不用慌!今天我来教大家如何通过上网工具,轻松禁用Adobe验证的联网流量,彻底解决这个问题!

qq_34093397的博客 3万+

【AAAI 2025】轻量级特征增强新范式!FCM 模块助力小目标检测,即插即用提升模型泛化能力

本文介绍了AAAI 2025提出的轻量级特征增强新范式FCM模块,它通过显式分离并双向交互语义与空间特征,有效解决了小目标检测中特征信息失配的核心难题。该模块设计精巧,计算开销极低,能够即插即用式地嵌入YOLO等主流检测网络,显著提升模型对小目标的泛化检测能力,尤其适用于遥感、自动驾驶等对计算资源敏感的实际场景。

weixin_29056145的博客 287

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

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

m0_58154870的博客 1145

ESP32锂电池电量检测实战:从引脚选择到低功耗优化(附完整电路图)

本文详细介绍了ESP32锂电池电量检测的实战方案,从ADC引脚选择到低功耗优化,提供完整的电路图和代码实现。通过MOS管智能开关和深度睡眠技术,显著降低静态功耗至0.5μA,提升设备续航能力。适合物联网开发者解决电量检测中的常见问题。

weixin_28731223的博客 462

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

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

chuixue24的博客 196

MATLAB - Gazebo 联合仿真 —— 使用 UR10 机械臂检测和采摘水果

本示例演示如何在 Gazebo 物理模拟器中设置 Universal Robotics UR10 机械臂和仿真环境。您需要配置一个机器人从树上摘苹果的仿真环境。本示例演示如何利用这些工具箱,使用 Universal Robotics UR10 机械手模拟机器人检测并从树上摘取苹果。Robotics System Toolbox™ - 在 Simulink® 和 Gazebo 中对机械手进行建模、规划和模拟。Navigation Toolbox™ - 生成三维环境的占用图。

机器人控制与仿真应用 4182

【Proteus仿真】用24C04与1602LCD设计的简易加密电子密码锁

【Proteus仿真】用24C04与1602LCD设计的简易加密电子密码锁

perseverance51博客 1121

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

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

qq_58284486的博客 673

成本中心(CO)和利润中心(PCA)是管理会计模块的核心组件

SAP中成本中心(CO)和利润中心(PCA)凭证处理存在差异:①外部交易(如费用支付、销售)会生成FI借贷凭证;②内部成本分摊和转移仅产生CO/PCA管理凭证,通过次级成本要素或利润中心转移科目记录,不涉及FI模块。核心区别在于是否涉及企业实际收支:实际收支触发FI凭证,内部核算仅生成管理会计凭证。系统通过这种机制实现财务会计与管理会计的集成与分离。

金牌架构师 1127

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

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

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

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

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

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

Blog of Jatsby 319

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

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

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

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
上一篇: 算法数据结构-树(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、付费专栏及课程。

余额充值