在前面一片文章《JVM内部细节之一:synchronized关键字及实现细节》中已经提到过偏向锁的概念,在理解什么是偏向锁前必须先理解什么是轻量级锁(Lightweight Locking)。引入偏向锁是为了在无多线程竞争的状况下尽可能减小没必要要的轻量级锁执行路径,由于轻量级锁的获取及释放依赖屡次CAS原子指令,而偏向锁只须要在置换ThreadID的时候依赖一次CAS原子指令(因为一旦出现多线程竞争的状况就必须撤销偏向锁,因此偏向锁的撤销操做的性能损耗必须小于节省下来的CAS原子指令的性能消耗)。下面看具体细节:html
1、对象头中的Mark Word布局java
在上一篇文章中所讨论的轻量级锁中在我参考的Paper中对于重量级锁的实现并无经过状态位来表现而是直接经过在轻量级锁的Monitor Record中关联一个底层操做系统的互斥信号量来实现重量级锁的操做(并不影响咱们理解JVM内部锁的运做过程),在偏向锁的处理过程当中并不涉及重量级锁,咱们这里只须要关心biasable和lightweight locked两种状态。在JDK1.6之后默认已经开启了偏向锁这个优化,咱们能够经过在启动JVM的时候加上-XX:-UseBiasedLocking参数来禁用偏向锁(在存在大量锁对象的建立并高度并发的环境下禁用偏向锁可以带来必定的性能优化)。安全
2、偏向锁的获取过程(假设开启了偏向锁优化):性能优化
(1)初始时对象处于biasable状态,而且ThreadID为0即biasable & unbiased状态(这里不讨论epoch和age)多线程
(2)当一个线程试图锁住一个处于biasable & unbiased状态的对象时,经过一个CAS将本身的ThreadID放置到Mark Word中相应的位置,若是CAS操做成功进入第(3)步不然进入(4)步并发
(3)当进入到这一步时表明当前没有锁竞争,Object继续保持biasable状态,可是这时ThreadID字段被设置成了偏向锁全部者的ID,而后进入到第(6)步oracle
(4)当前线程执行CAS获取偏向锁失败(这一步是偏向锁的关键),表示在该锁对象上存在竞争而且这个时候另一个线程得到偏向锁全部权。当到达全局安全点(safepoint)时得到偏向锁的线程被挂起,并从偏向锁全部者的私有Monitor Record列表中获取一个空闲的记录,并将Object设置为LightWeight Lock状态而且Mark Word中的LockRecord指向刚才持有偏向锁线程的Monitor record,最后被阻塞在安全点的线程被释放,进入到轻量级锁的执行路径中,同时被撤销偏向锁的线程继续往下执行同步代码。oop
(5)当一个线程试图锁住一个处于biasable & biased而且ThreadID不等于本身的ID时,这时因为存在锁竞争必须进入到第(4)步来撤销偏向锁。布局
(6)运行同步代码块性能
2、偏向锁的解锁过程:
(1)偏向锁解锁过程很简单,只须要测试下是否Object上的偏向锁模式是否还存在,若是存在则解锁成功不须要任何其余额外的操做。
3、参考资料: