`
m635674608
  • 浏览: 4932915 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

JVM中锁优化简介

 
阅读更多

自旋锁

互斥同步对性能最大的影响是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性能带来了很大的压力。而在很多应用上,共享数据的锁定状态只会持续很短的一段时间。若实体机上有多个处理器,能让两个以上的线程同时并行执行,我们就可以让后面请求锁的那个线程原地自旋(不放弃CPU时间),看看持有锁的线程是否很快就会释放锁。为了让线程等待,我们只须让线程执行一个忙循环(自旋),这项技术就是自旋锁。

如果锁长时间被占用,则浪费处理器资源,因此自旋等待的时间必须要有一定的限度,如果自旋超过了限定的次数仍然没有成功获得锁,就应当使用传统的方式去挂起线程了(默认10次)。

JDK1.6引入自适应的自旋锁:自旋时间不再固定,由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而它将允许自旋等待持续相对更长的时间。

锁削除

锁削除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行削除(主要判定依据来源于逃逸分析的数据支持,如果判断到一段代码中,在堆上的所有数据都不会逃逸出去被其他线程访问到,那就可以把它们当作栈上数据对待,认为它们是线程私有的,同步加锁自然就无须进行)。

锁膨胀

如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中的,那即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。 如果虚拟机探测到有这样一串零碎的操作都对同一个对象加锁,将会把加锁同步的范围扩展(膨胀)到整个操作序列的外部(由多次加锁编程只加锁一次)。

轻量级锁

轻量级锁并不是用来代替重量级锁(传统锁机制,如互斥等)的,目的是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

HotSpot虚拟机的对象头(Object Header)分为两部分信息,第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄(Generational GC Age)等,这部分数据的长度在32位和64位的虚拟机中分别为32个和64个Bits,官方称它为“Mark Word”,它是实现轻量级锁和偏向锁的关键。另外一部分用于存储指向方法区对象类型数据的指针,如果是数组对象的话,还会有一个额外的部分用于存储数组长度。

Mark Word被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。例如在32位的HotSpot虚拟机中对象未被锁定的状态下,Mark Word的32个Bits空间中的25Bits用于存储对象哈希码(HashCode),4Bits用于存储对象分代年龄,2Bits用于存储锁标志位,1Bit固定为0,在其他状态(轻量级锁定、重量级锁定、GC标记、可偏向)下Mark Word的存储内容如下表所示。

存储内容 标志位 状态
对象Hash值、对象分代年龄 01 未锁定
指向锁记录的指针 00 轻量级锁定
指向重量级锁的指针 10 膨胀(重量级锁定)
空,不记录信息 11 GC标记
偏向线程ID、偏向时间戳、对象分代年龄 01 可偏向

加锁过程

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

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

如果这个更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁,锁标志的状态值变为“10”,Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也要进入阻塞状态。

解锁过程

解锁过程也是通过CAS操作来进行的,如果对象的Mark Word仍然指向着线程的锁记录,那就用CAS操作把对象当前的Mark Word和线程中复制的Displaced Mark Word替换回来,如果替换成功,整个同步过程就完成了。如果替换失败,说明有其他线程尝试过获取该锁,那就要在释放锁的同时,唤醒被挂起的线程。

轻量级锁小结

轻量级锁能提升程序同步性能的依据是“对于绝大部分的锁,在整个同步周期内都是不存在竞争的”,这是一个经验数据。如果没有竞争,轻量级锁使用CAS操作避免了使用互斥量的开销,但如果存在锁竞争,除了互斥量的开销外,还额外发生了CAS操作,因此在有竞争的情况下,轻量级锁会比传统的重量级锁更慢。

偏向锁

目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。如果说轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,那偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS操作都不做了。

偏向锁会偏向于第一个获得它的线程(Mark Word中的偏向线程ID信息),如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。

假设当前虚拟机启用了偏向锁(启用参数-XX:+UseBiasedLocking,JDK 1.6的默认值),当锁对象第一次被线程获取的时候,虚拟机将会把对象头中的标志位设为“01”,即偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark Word之中,如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作(例如Locking、Unlocking及对Mark Word的Update等)。    当有另外一个线程去尝试获取这个锁时,偏向模式就宣告结束。根据锁对象目前是否处于被锁定的状态,撤销偏向(Revoke Bias)后恢复到未锁定(标志位为“01”)或轻量级锁定(标志位为“00”)的状态,后续的同步操作就如上面介绍的轻量级锁那样执行。偏向锁、轻量级锁的状态转化及对象Mark Word的关系如下图所示。

偏向锁可以提高带有同步但无竞争的程序性能。它同样是一个带有效益权衡(Trade Off)性质的优化,也就是说它并不一定总是对程序运行有利,如果程序中大多数的锁都总是被多个不同的线程访问,那偏向模式就是多余的。

主要参考

  1. 《深入理解Java虚拟机:JVM高级特性与最佳实践》
  2. The Hotspot Java Virtual Machine
  3. Eliminating Synchronization-Related Atomic Operations with Biased Locking and Bulk Rebiasing

http://www.importnew.com/15340.html

分享到:
评论

相关推荐

    实战Java虚拟机——JVM故障诊断与性能优化 pdf

    《实战Java虚拟机——JVM故障诊断与性能优化》内容简介:随着越来越多的第三方语言(Groovy、Scala、JRuby等)在Java虚拟机上运行,Java也俨然成为一个充满活力的生态圈。本书将通过200余示例详细介绍Java虚拟机中的...

    深入JVM内核 - 原理、诊断与优化

    介绍JVM中对多线程锁的实现。 第十课 class文件结构 ASM库介绍 介绍JVM规范中的最重要的内容——Class文件结构,同时介绍ASM库的使用以及对class文件的修改。 第十一课 字节码执行 案例以及javap JIT及相关参数 ...

    实战JAVA虚拟机 JVM故障诊断与性能优化

    本书将通过200余示例详细介绍Java虚拟机中的各种参数配置、故障排查、性能监控以及性能优化。  本书共11章。第1~3章介绍了Java虚拟机的定义、总体架构、常用配置参数。第4~5章介绍了垃圾回收的算法和各种垃圾回收器...

    jvm细节探索之synchronized及实现问题分析

    主要介绍了jvm细节探索之synchronized及实现问题分析,涉及synchronized的字节码表示,JVM中锁的优化,对象头的介绍等相关内容,具有一定借鉴价值,需要的朋友可以参考下。

    JVM 规范(JDK7.0)

    主要描述了JVM结构组成、对编译后的class文件格式、对class文件的校验(class文件校验器)、jvm指令、JVM中对线程和锁的处理机制、以及sun虚拟机 的具体实现的优化(使用quick伪指令),对于想了解JVM运行细节,字节...

    Java面试题mysql数据库和jvm知识面试题用于技能提升和面试提升

    八、在MySQL中,事务提交与回滚 10 九、事务四大特性之一隔离性(isolation) 11 十、隔离级别与一致性关系 12 十一、设置事务隔离级别 12 十二、隔离级别的作用范围 12 十三、查看隔离级别 12 DB索引 13 MySQL索引的...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    / 342 13.1 概述 / 342 13.2 线程安全 / 343 13.2.1 Java语言中的线程安全 / 343 13.2.2 线程安全的实现方法 / 348 13.3 锁优化 / 356 13.3.1 自旋锁与自适应自旋 / 356 13.3.2 锁消除 / 357 13.3.3 锁粗化 ...

    Java多线程和并发知识整理

    3.3 JVM中锁的优化 3.4 Synchronized与Lock 3.5 扩展 四、volatile 详解 4.1 作用 4.2 实现原理 4.3 应用场景 五、final 详解 5.1 基础 5.2 重排序规则 5.3 扩展 六、JUC 6.1 汇总 6.2 Lock框架和Tools类...

    Java性能调优实战——覆盖80%以上的Java应用调优场景

    避免使用Java序列化14讲多线程之锁优化(下):使用乐观锁优化并行操作16讲多线程调优(下):如何优化多线程上下文切换17讲并发容器的使用:识别不同场景下最优容器21讲深入JVM即时编译器JIT,优化Java编译25讲答疑...

    并发编程中是如何降低锁粒度的,怎么做到性能优化!.docx

    在本文中,我会向你介绍一种通过降低锁粒度的技术来减少这些因素。 让我们从一个基本原则开始:不要长时间持有不必要的锁。 在获得锁之前做完所有需要做的事,只把锁用在需要同步的资源上,用完之后立即释放它。我们...

    Java理论与实践:Mustang中的同步优化

    本文描述的是Sun的HotSpot JVM实现未来版本的特性。每当易变的变量在线程间共享时,都必须使用同步来确保一个线程所...本文还介绍了JVM对于竞争锁请求和非竞争锁请求有不同的代码路径,分别是“慢路径”和“快路径”。

    java最新高薪面试题库.docx

    什么是Java虚拟机(JVM)?它如何工作? 什么是垃圾回收?Java中的垃圾回收是如何实现的? Java中的锁机制有哪些?它们有什么区别? 什么是线程安全?在Java中如何实现线程安全?...如何优化锁竞争?

    2019互联网面试题第2季.mmap

    包括JUC多线程并发、JVM和GC等目前大厂笔试中会考、面试中会问、工作中会用的高频难点知识。上半场,从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、阻塞队列、...

    【原价2300!!】尚硅谷_互联网大厂高频重点面试题视频详细讲解

    JUC多线程并发、JVM和GC等目前大厂笔试中会考、面试中会问、工作中会用的高频难点知识。上半场,从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、阻塞队列、...

    java关键字Synchronized详解

    此时,如果其他线程试图获取该对象的锁,JVM会将对象头中的Mark Word(指向对象头的指针)设置为偏向锁标识。这样,只有当前线程才能访问该对象,其他线程需要等待偏向锁失效后才能继续执行。 当一个线程释放偏向锁时...

    2019年互联网大厂高频重点面试题(第2季)

    本期内容包括JUC多线程并发、JVM和GC等目前大厂笔试中会考、面试中会问、工作中会用的高频难点知识。上半场,从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、...

    java高并发相关知识点.docx

    性能优化:Java中的性能优化,包括JVM参数调优、代码优化、使用并发框架等。 并行计算:Java中的并行计算,包括Fork/Join框架、并行流等。 线程间通信:Java中的线程间通信,包括wait()、notify()、notifyAll()等...

Global site tag (gtag.js) - Google Analytics