Synchronized原理和jdk1.8后的优化

systrace分析 之 问题初步定位 如下surfaceflinger空缺点,上面对应的bufferTX 中有buffer,但VSYNC-SF 过来后,SurfaceFlinger却没有去取,检查测试app “android.settings”, 也没有GPU completion 时间长的问题,所以该部分可以请SurfaceFlinger的owner 进一步确认为何不取buffer。. GPU拿的是acquireFence HWC拿的是releaseFence, GPU是绘图,HWC是合成显示,这两个是互相等待的关系, 阅读详情

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

柑橘病虫害识别方案总结 1. 方案一 1.1 赛题背景 1.2 数据分析 1.3 模型设计 1.3.1 模型具体方案 1.3.2 模型设计 1.4 实验结果 1.5 总结与展望 2. 方案二 2.1 赛题介绍 2.2 数据分析 2.3 算法方案解析 2.3.1 检测模型 2.3.2 提升策略 2.4 优化思路 3. 方案三 3.1 数据分析 3.1.1 数据说明 3.2 技术展示 3.2.1 数据输入端 3.2.2 模型结构端 3.2.3 上下文信息 3.2.4 训练优化端 3.2.5 创新性分析 3.3 算法及系统思考..... 阅读详情

相关推荐

Apple 网页 SRP 登录系列文章(二):网页参数提取与会话初始化

本文深入解析了Apple网页SRP登录的第一个关键环节。文章首先指出Apple登录页面采用多层安全架构,包括跨域跳转机制和动态参数生成。重点介绍了四种关键参数(ServiceKey、SCNT、FrameId、ServiceNum)的提取技术,通过正则表达式和JSON路径解析从HTML脚本和HTTP头中获取。最后详细说明了会话初始化流程,包括访问初始页面和构建认证URL。这些技术细节揭示了Apple如何通过复杂机制确保登录过程的安全性。

Sayid_Des的专栏 1129

Java Synchronized

synchronized

Monkey_4 882

python 抖音采集_python爬取抖音视频的实例详解

import requestsimport jsonimport reimport osfrom pprint import pprint as ppimport queueclass DouYin:header = {'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*...

weixin_35795675的博客 1864

jdk1.8对synchronized锁的优化

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

常敲代码手不生 4783

Deep Reinforcement Learning - 1. DDPG原理和算法

Deep Reinforcement Learning - 1. DDPG原理和算法 背景描述 DDPG的定义和应用场景 DDPG算法相关基本概念定义 DDPG实现框架和算法 DDPG对于DPG的关键改进 下一篇 以下用RL作为Reinforcement Learning 的简称。背景描述概括来说,RL要解决的问

kenneth_yu的博客 14万+

UNITE真菌数据库使用避坑指南:从下载到注释的完整流程

本文提供了UNITE真菌数据库从下载到注释的完整实战指南。针对真菌ITS序列分析,重点解析了数据库版本选择、格式转换的常见陷阱,并详细介绍了如何训练优化的sklearn分类器以提升物种注释的精度和可靠性,帮助用户构建高效稳定的本地工作流。

weixin_29240343的博客 199

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

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

m0_58154870的博客 1145

OpenStack [ compute_id ] 设计上的小缺陷

而 nova 代码中硬编码(或默认配置)将 compute_id 放在 site-packages 目录,属于 设计上的小缺陷—— 把 “库安装目录” 和 “运行时数据目录” 混在一起了,才导致需要临时调整这个目录的权限。# 配置项说明:node_identity_file 是 nova 用于指定节点标识文件路径的官方配置项,优先级高于代码中的默认路径。自定义 compute_id 路径,指向 /var/lib/nova/ 目录下的 compute_id 文件;

求知若渴,虚心若愚。 491

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

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

chuixue24的博客 196

干货|C#上位机与西门子PLC的Profinet协议通信开发(工控机版)

文章摘要: Profinet是西门子主导的工业以太网协议,支持实时通信(RT/IRT),广泛应用于PLC与工控机通信。本文聚焦C#上位机通过S7协议(集成于Profinet接口)高效访问西门子PLC(S7-1200/1500等),提供完整开发方案: 协议基础:解析Profinet三层架构(TCP/IP层、实时层、应用层),对比S7协议优势(开发便捷、跨平台); 开发实践:基于S7NetPlus/Snap7库实现数据读写,涵盖DB块、I/O点等地址规则; 环境配置:工控机(Windows/Linux/统信UO

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1213

fatal: unable to access ‘https://github.com/xxx.git/‘ OpenSSL SSL_connect: SSL_ERROR_SYSCALL 解决方案

 本文主要介绍了fatal: unable to access ‘https://github.com/xxx.git/’: OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443解决方案,希望能对使用git的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 24万+

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

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

qq_58284486的博客 673

VSCode PlantUML 插件超详细教程:从安装配置到实战绘图全流程

VSCode PlantUML 插件超详细教程:从安装配置到实战绘图全流程

weixin_69237381的博客 909

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

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

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

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

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

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

Blog of Jatsby 319

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

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

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

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

余额充值