在另外的两篇文章中先后介绍了轻量级同步关键字volatile和重量级锁关键字synchronized,这两个关键字是Java语言中进行线程同步的基本方式(当然还有ReentrenLock等显式锁方式)。本文将就Java虚拟机针对同步原语做的一些锁优化进行简单的介绍,同时基于JDK 1.6将这些锁优化措施设置为默认值,对锁的获取流程进行图示。

锁优化

1、自旋锁与自适应自旋

我们知道,互斥同步时候,对性能影响最大的是阻塞的实现,挂起线程和恢复线程都需要陷入内核态去完成,而频繁的用户态内核态切换势必会造成频繁的上下文切换从而影响了性能,所以自旋锁就出现了,如果共享资源的占用时间不是很长的话,想要进入临界区的线程完全可以不放弃处理器的执行时间,只要执行一个忙循环即可。但是资源的占用时间也不是我们可以凭空想象的,所以我们可以通过-XX:PreBlockSpin参数来修改自旋次数,如果忙循环的循环次数大于了设置的自旋次数,那么还是执行原来的方式挂起线程。

2、锁消除

锁消除是指虚拟机在编译器运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。比如在判断一段代码中,堆上的数据都不会逃逸出去从而被其他的线程访问到,那么可以认为他们是线程私有的,同步加锁自然无须进行。

3、所粗化

我们熟悉的是减小锁的粒度如锁分解和锁分段等优化措施,但有的时候,如果一系列的连续操作对都对一个对象反复加锁和减锁,甚至枷锁操作是出现在循环体中的,那么即使没有线程竞争,频繁的进行互斥同步操作也会导致不必要的性能损耗。(注意:这项优化措施似乎在有了偏向锁和轻量级锁后就不太需要了---个人感觉)

4、轻量级锁

轻量级锁匙JDK 1.6之后新加入的新型锁机制,它的实现和后面的偏向锁的实现都需要Java对象头MarkWord信息的帮助

对象头中的MarkWord信息是可以复用的,复用的具体情况如上图所示。在代码进入同步块时,如果此对象没有被锁定(锁标志位“01”状态),虚拟机将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的MarkWord拷贝(官方把这份拷贝加了一个Displaced前缀,即Displaced Mark Word)

然后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针,如果这个更新成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位(Mark Word的最后2bit)将转变为“00”,即表示此对象处于轻量级锁定状态

如果更新失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果只说明了当前线程已经拥有了这个对象的锁,那就可以直接进入同步块执行,否则则说明这个锁对象已经被其他线程抢占了。如果有两个不同的线程抢占同一个锁,那么轻量级锁就会膨胀为重量级锁(互斥同步)

5、偏向锁

偏向锁的目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。轻量级锁匙在无竞争的情况下使用CAS操作去消除同步使用的互斥量,那偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS也不要了。它的实现原理和轻量级锁一样,也是和对象头的Mark Word相关。

结合所有的锁优化步骤,那么代码执行锁获取操作的流程如下图所示

参考资料:《深入理解Java虚拟机》---周志明

JAVA并发之锁获取步骤及锁优化的更多相关文章

  1. Java并发之彻底搞懂偏向锁升级为轻量级锁

    网上有许多讲偏向锁,轻量级锁的文章,但对偏向锁如何升级讲的不够明白,有些文章还相互矛盾,经过对jvm源码(biasedLocking.cpp)的仔细分析和追踪,基本升级过程有了一个清晰的过程,现将升级 ...

  2. Java多线程(五) —— 线程并发库之锁机制

    参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...

  3. JVM锁简介:偏向锁、轻量级锁和重量级锁

    转自:https://www.aimoon.site/blog/2018/05/21/biased-locking/ 比较复杂,简略见另一篇:https://www.cnblogs.com/twohe ...

  4. 001-多线程-锁-架构【同步锁、JUC锁】

    一.概述 Java中的锁,可以分为"同步锁"和"JUC包中的锁". 1.1.同步锁 即通过synchronized关键字来进行同步,实现对竞争资源的互斥访问的锁 ...

  5. java并发之线程同步(synchronized和锁机制)

    使用synchronized实现同步方法 使用非依赖属性实现同步 在同步块中使用条件(wait(),notify(),notifyAll()) 使用锁实现同步 使用读写锁实现同步数据访问 修改锁的公平 ...

  6. Java并发之显式锁和隐式锁的区别

    Java并发之显式锁和隐式锁的区别 在面试的过程中有可能会问到:在Java并发编程中,锁有两种实现:使用隐式锁和使用显示锁分别是什么?两者的区别是什么?所谓的显式锁和隐式锁的区别也就是说说Synchr ...

  7. Java并发之锁升级:无锁->偏向锁->轻量级锁->重量级锁

    Java并发之锁升级:无锁->偏向锁->轻量级锁->重量级锁 对象头markword 在lock_bits为01的大前提下,只有当是否偏向锁位值为1的时候,才表明当前对象处于偏向锁定 ...

  8. 转 Java并发之锁的升级

    说明:本文大部分内容来自<并发编程的艺术>,再加上自己网络整理和理解 以下内容来自<java并发编程的艺术>作者:方鹏飞 魏鹏 程晓明 在多线程并发编程中synchronize ...

  9. Java并发之(3):锁

    锁是并发编程中的重要概念,用来控制多个线程对同一资源的并发访问,在支持并发的编程语言中都有体现,比如c++ python等.本文主要讲解Java中的锁,或者说是重入锁.之所以这么说是因为在Java中, ...

随机推荐

  1. 获取checkbox返回值

    <div class="checkbox"> <label> <input type="checkbox" value=" ...

  2. 自然语言处理课程(二):Jieba分词的原理及实例操作

    上节课,我们学习了自然语言处理课程(一):自然语言处理在网文改编市场的应用,了解了相关的基础理论.接下来,我们将要了解一些具体的.可操作的技术方法. 作为小说爱好者的你,是否有设想过通过一些计算机工具 ...

  3. [Err] 1062 - Duplicate entry '0' for key 'PRIMARY'

    问题描述: sql语句执行的时候,插入语句无法正确执行 问题原因: 主键 重复 出现 0 解决方案: 将主键设置为自增 然而,设置自增后还是可能会出现下面的问题 #1062 – Duplicate e ...

  4. JS拉平数组

    JS拉平数组 有时候会遇到一个数组里边有多个数组的情况(多维数组),然后你想把它拉平使其成为一个一维数组,其实最简单的一个方法就是ES6数组方法Array.prototype.flat.使用方法如下: ...

  5. Postman接口测试工具学习笔记

    - 新建测试接口 在Postman中有两种新建测试接口的方式,第一种是图片右上角的,点击可以选择 request 请求进行新建 选择 Request 以后会出现下面图片的对话框,让你输入一个保存接口的 ...

  6. 洛谷P1809 过河问题 经典贪心问题

    作者:zifeiy 标签:贪心 题目链接:https://www.luogu.org/problem/P1809 我们假设第 \(i\) 个人过河的耗时是 \(t[i]\) ,并且 \(t[i]\) ...

  7. H3C 传递信息

  8. Java语言中的正则表达式

    正则表达式是什么? 正则表达式是一种强大而灵活的文本处理工具.初学正则表达式时,其语法是一个难点,但它确实是一种简洁.动态的语言.正则表达式提供了一种完全通用的方式,能够解决各种字符串处理相关的问题: ...

  9. P1068 压缩技术

    题目描述 设某汉字由N × N的0和1的点阵图案组成. 我们依照以下规则生成压缩码.连续一组数值:从汉字点阵图案的第一行第一个符号开始计算,按书写顺序从左到右,由上至下.第一个数表示连续有几个0,第二 ...

  10. H3C 端口隔离基本配置