Synchronized原理和jdk1.8后的优化

Windows 10下Carla 0.9.15安装避坑指南:从下载到运行的全流程解析 本文详细解析了在Windows 10系统上安装和运行Carla 0.9.15自动驾驶仿真平台的全流程。内容涵盖从系统环境准备、资源下载、Python依赖安装,到首次启动验证及常见错误(如DLL缺失、显卡驱动问题)的深度解决方案,旨在帮助用户快速搭建稳定的开发环境,并运行第一个自动驾驶Python脚本。 阅读详情

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

【DRAM存储器五十七】LPDDR5介绍--read DQ training和WCK DQ training 简述LPDDR5训练中的读写DQ训练 阅读详情

相关推荐

抖音直播小风车跳转企业微信全攻略:企业号申请+落地页配置详解

本文详细解析了抖音直播小风车跳转企业微信的全流程,包括企业号申请、小风车配置和落地页优化。通过实战指南,帮助企业高效实现私域流量沉淀,提升直播转化率,特别适合电商和营销从业者参考。

weixin_29289821的博客 613

Java Synchronized

synchronized

Monkey_4 882

PyCharm安装PyQt5及工具(Qt Designer、PyUIC、PyRcc)详细教程来了

Qt是常用的用户界面设计工具,而在Python中则使用PyQt这一工具包,它是Python编程语言和Qt库的成功融合。这篇博文通过图文详细介绍在PyCharm中如何完整优雅地安装配置PyQt5的所有工具包,主要内容包括PyQt5、PyQt5-tools的依赖包安装和Qt Designer、PyUIC、PyRcc三个工具的设置。最后简单演示了PyQt5的调用方式及三个工具的使用方法。

Python966的博客 3万+

jdk1.8对synchronized锁的优化

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

常敲代码手不生 4783

Python+Vue计算机毕业设计风电场监控系统的设计与实现7bd6i(程序+LW+源码+部署)

Python3.7.7+Django+Mysql5.7+pip list+HBuilderX(Vscode也行)+Vue+Pychram社区版。2. 前端:vue+css+javascript+jQuery+easyUI+highcharts。2.IDE环境:Python和Python 社区版都可以。Django + Vue +Python+Mysql 等等组成,B/S模式等等。该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。1. 后端:Python、Vue、Django、Mysql。

华信计算机毕设源码程序 341

雷光联动自动化标校方法

动态标校需要利用动目标,在雷达和光电同时看到目标时记录光电的方位、俯仰,以及利用雷达给的目标信息计算的方位俯仰,手动记录两者的数值,多方位,多距离段记录,费时费力,且人工记录数据不全,计算容易出差错,耗费成本和精力太大。目标相距设备的水平距离 = acos(cos(设备纬度弧度值) * cos(目标纬度弧度值) * cos(设备经度弧度值 – 目标经度弧度值) + sin(设备纬度弧度值) * sin(目标纬度弧度值)) * 6378137;本发明涉及光电技术领域,安防领域,尤其涉及雷达光电动态标校等。

u013358093的博客 1580

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

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

m0_58154870的博客 1145

win10下面安装MTK USB VCOM 驱动

win10下面安装MTK USB VCOM 驱动1.概述2.驱动准备3.主要步骤3.1禁用win10对没有签名驱动限制3.2通过设备管理器安装mtk usb vcom驱动3.3工具版本问题4.禁用win10对没有签名的驱动限制4.1在设置中打开 更新和安全4.2进入恢复4.3在高级启动中点击立即重新启动4.4电脑重启后的几个动作5.通过设备管理器安装MTK USB VCOM 驱动5.1准备驱动5....

qimi123456的专栏 3万+

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

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

chuixue24的博客 196

某手短视频用户主页视频列表爬虫实战:从原理到完整实现

随着短视频平台的迅猛发展,某手(为保护平台隐私,本文以“某手”代指实际目标)已经成为国内最大的短视频社交平台之一,拥有数亿日活用户。对于数据分析师、内容创作者和市场营销人员而言,获取某个用户主页的视频列表具有重要的研究价值——无论是分析头部创作者的内容策略,还是监测竞品的发布频率与互动数据,爬虫技术都成为不可或缺的工具。然而,在2024-2025年的技术环境下,某手已经构建了多层次的反爬机制:包括接口签名加密、请求参数动态混淆、设备指纹检测、IP行为分析以及Web端无限滚动加载的异步数据获取方式。

2201_76125261的博客 540

Android 14.0 开机广播接收慢广播延迟问题分析

在14.0的系统rom定制化开发中,在某些时候在接收开机广播的时候发现,过了一分钟才收到开机广播,接下来就需要分析下 开机广播的相关分发机制,来处理下相关问题

安卓兼职framework和app工程师的博客 631

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

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

qq_58284486的博客 673

【100%通过率】华为OD机试真题2026双机位C卷 C语言 实现【加密算法】

【100%通过率】华为OD机试真题2026双机位C卷 Python&JS 实现【加密算法】有一种特殊的加密算法,明文为一段数字串,经过密码本查找转换,生成另一段密文数字串。规则如下

MISAYAONE的博客 647

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

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

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

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

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

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

Blog of Jatsby 319

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

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

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

Statistics and Machine Learning Toolbox

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

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、付费专栏及课程。

余额充值