乱弹java并发(七)-- 轻量级锁、偏向锁

来源:互联网 发布:mysql 取一条记录 编辑:程序博客网 时间:2024/06/05 17:34

java6之前的同步时依赖操作系统互斥来实现的,互斥会导致频繁的线程上下文切换,消耗CPU资源,java6在HotSpot中引入了轻量级锁和偏向锁机制来对同步进行优化,它们的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

要了解轻量级锁,以及后面讲到的偏向锁原理和运作过程,必须从虚拟机(HotSpot)的对象头的内存布局开始介绍。HotSpot虚拟机的对象头(普通对象8个字节,数组对象12个字节,多出来4个字节存储数组长度)分为两部分信息,第一部分用于存储对象自身的运行时数据,如HashCode、GC分代年龄(Generational GC Age)等,这部分数据在32位虚拟机中为32bit(4字节),官方称为“Mark Word”,它是实现轻量级锁和偏向锁的关键。另外一部分用于存储指向方法区对象类型数据的指针。
在Mark Word中,有2bit用来存储锁标志位:01,未锁定/可偏向;00,轻量级锁定;10,重量级锁定;11,GC标记,大致结构图如下:


轻量级锁的执行过程如下:
代码进入同步块时,如果此同步对象没有被锁定(锁标志位为“01”状态),虚拟机首先在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前Mark Word的拷贝(官方把这份拷贝加了一个Displaced前缀,即Displaced Mark Word)。然后,虚拟机将使用CAS操作尝试将对象的Mark Word的轻量级锁指针更新为指向Lock Record的指针,Lock Record的owner指针指向Mark Word。如果该CAS指令调用成功,那么这个线程就拥有了该对象的锁,并且对象的Mark Word的锁标志位将变成“00”,即表示此对象处于轻量级锁定状态。如果CAS更新失败则升级为重量级锁,锁标志位更新成“00”,Mark word指针指向重量级锁指针,并且调用OS互斥原语,挂起当前线程。
解锁的过程也是调用CAS指令,如果Mark Word仍旧指向当前lock record,且被拷贝的Mark word(displaced mark word)信息与mark word一致,则还原mark word指针和displaced mark word,CAS指令成功则解锁成功,如果指令调用失败,说明有其它线程尝试过获取该锁,那么在释放锁的同时还要唤醒被挂起的线程。

偏向锁也是JDK1.6已入的一项锁优化,它的目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,而偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS也不需要了。启用参数-XX:+UseBiasedLocking(JDK1.6默认)之后,虚拟机会启用偏向锁,那么,当锁对象第一次被线程获取时虚拟机会把Mark Word锁标识设成01即偏向模式。同时使用CAS操作把获取到锁线程的ID纪录在Mark Word中,如CAS调用成功,持有偏向锁的线程每次进入该锁的同步块时,虚拟机无需做任何同步操作。当有另外一个线程去尝试获取这个锁时,偏向模式就宣告结束。根据锁对象目前是否处于被锁定状态,撤销偏向后恢复到未锁定(标志位01)或轻量级锁状态(标志位00),后续的同步操作升级到轻量级锁流程。

无论是轻量级锁还是偏向锁都只有在无竞争的情况下才能达到优化消化,如果同一个锁总是不多个线程竞争,那么轻量级锁和偏向锁反而会比重量级锁更慢,因为多做了一些无谓的操作,可以通过-XX:-UseBiasedLocking来禁用偏向锁。

0 0
原创粉丝点击