java 轻量级锁原理 java轻量级锁解锁_java 轻量级锁原理


从Java SE 1.6开始,为了减少获得锁和释放锁带来的性能消耗,就引入了轻量级锁。轻量级锁在对象内存布局中 MarkWord 锁标志位为 00,它可以由偏向锁对象因存在多个线程访问而升级成轻量级锁,当然,轻量级锁也可能因多个线程同时访问同步代码块升级成重量级锁。

一、加锁过程

加锁过程主要分为3步:

1、在线程执行同步代码块之前,JVM会现在当前线程的栈桢中创建用于存储锁记录的空间,并将锁对象头中的 markWord 信息复制到锁记录中,这个官方称为 Displaced Mard Word。然后线程尝试使用 CAS 将对象头中的 MarkWord 替换为指向锁记录的指针。


java 轻量级锁原理 java轻量级锁解锁_同步代码块_02


2、将锁对象头中的 markWord 信息复制到锁记录中,这个官方称为 Displaced Mard Word。然后线程尝试使用 CAS 将对象头中的 MarkWord 替换为指向锁记录的指针。如果替换成功,则进入步骤3,失败则进入步骤4。

3、CAS 替换成功说明当前线程已获得该锁,此时在栈桢中锁标志位信息也更新为轻量级锁状态:00。此时的栈桢与锁对象头的状态如图二所示。


java 轻量级锁原理 java轻量级锁解锁_同步代码块_03

图二

4、如果CAS 替换失败则说明当前时间锁对象已被某个线程占有,那么此时当前线程只有通过自旋的方式去获取锁。如果在自旋一定次数后仍为获得锁,那么轻量级锁将会升级成重量级锁。

升级成重量级锁带来的变化就是对象头中锁标志位将变为 10(重量级锁),MarkWord 中存储的也就是指向互斥量(重量级锁)的指针。(注意!!!此时,锁对象头的 MarkWord 已经发生了改变)。

轻量级锁升级过程大概流程图如下:


java 轻量级锁原理 java轻量级锁解锁_同步代码块_04

图三

2、解锁过程

轻量级锁解锁时,会使用CAS将之前复制在栈桢中的 Displaced Mard Word 替换回 Mark Word 中。如果替换成功,则说明整个过程都成功执行,期间没有其他线程访问同步代码块。

但如果替换失败了,表示当前线程在执行同步代码块期间,有其他线程也在访问,当前锁资源是存在竞争的,那么锁将会膨胀成重量级锁。图三中重量级锁部分也就眼神了锁膨胀的过程。

3、轻量级锁的优缺点

轻量级锁涉及到一个自旋的问题,而自旋操作是会消耗CPU资源的。为了避免无用的自旋,当锁资源存在线程竞争时,偏向锁就会升级为重量级锁来避免其他线程无用的自旋操作。所以这就引出了偏向锁的一个缺点:如果始终无法获得锁资源,线程就会自旋消耗CPU资源。

但是偏向锁相对于重量级锁的一个有点就是:因为线程在竞争资源时采用的是自旋,而不是阻塞,也就避免了线程的切换带来的时间消耗,提高了程序的响应速度。