HotSpot中的几种锁优化技术

在JDK 1.6中,HotSpot虚拟机实现不少锁优化技术来提高程序的执行效率。

自旋锁

自旋锁可以使线程在没有取得锁的时候不被挂起,而转去执行一个空循环。这样可以避免线程切换的开销,在锁被占用时间很短时对性能有所提高。反之,如果锁占用时间过长,那么自旋的线程只会白白消耗处理器资源。在jdk 1.6中还引入了自适应的自旋锁,即锁的自旋次数不在固定,而是根由前一次在同一个锁的自旋时间及锁的拥有者的状态来决定。

偏向锁

这是JDK 1.6引入的一项锁优化技术,其核心思想是,在无竞争的情况下,取消之前已经取得锁的线程同步操作。其过程为,当锁对象第一次被线程获取的时候,虚拟机将会把对象头中的标志位设为"01",即偏向模式,同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark Word之中,如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作。

注1:Mark Word(参考【理解HotSpot虚拟机】对象在jvm中的表示:OOP-Klass模型)

在HotSpot虚拟机中,对象表示被设计为一个OOP-Klass模型,其中OOP指的是Ordinary Object Pointer,用来表示对象的实例信息,而Klass则包含元数据和方法信息,用来描述类。Klass是在类加载时在方法区创建,表示其元数据(字段、方法等)。

而我们这里要重点讲的是OOP对象,其包含两部分:对象头、实例对象和对齐填充。对象头又分两部分:

  1. Mark Word,用于存储对象自身的运行时数据,如哈希码,GC分代年龄等,是实现偏向锁和轻量级锁的关键
  2. 元数据指针,用于存储指向方法区instanceKlass实例,如果是数组对象的话,还会有一个额外的部分用于存储数组长度

HotSpot中的几种锁优化技术_第1张图片

注2:CAS(compare and swap)

CAS是设计并发算法时用到的一种技术,简单来说,就是在更新值前进行一次比较,比较结果正确后才进行赋值。

CAS指令需要有3个操作数,分别是内存位置(java中可简单理解为变量的内存地址,用V表示)、旧的预期地址(用A表示)和新值(用B)表示。CAS指令执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则它就不更新,但是无论是否更新了V的值,都会返回V的旧值,上述操作是一个原子操作。

轻量级锁

这也是JDK 1.6引入的新型锁机制。它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。即当另一个线程去尝试获取处于偏向模式的锁时,偏向模式就宣告结束了。Java虚拟机就会让线程申请轻量级锁。

其过程如下:在代码进入同步块时,如果此同步对象没有被锁定,虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储Mark Word的拷贝。然后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针。如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位将变成"00",即表示此对象处于轻量级锁状态。

轻量级锁使用CAS操作避免了使用互斥量的开销,但如果存在锁竞争,除了互斥量的开销外,还额外发生了CAS操作,因此,在此情景下,轻量级锁会比传统的重量级锁更慢。

锁消除及锁粗化

锁消除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。如:在单线程中使用jdk提供的线程安全的类。

锁粗化是指如果虚拟机探测到有这样一串零碎的操作都是对同一个对象加锁,为了避免频繁地进行互斥同步操作造成的性能损耗,将会把加锁同步的范围扩展(粗化)到整个操作序列的外部。

 

参考:《深入理解Java虚拟机》

 

你可能感兴趣的:(jvm)