• 1.适应性自旋
  • 2.锁消除
  • 3.锁粗化
  • 4.轻量级锁
  • 5.偏向锁

1.适应性自旋

自旋锁:

互斥同步对象能最大的影响就是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性能你带来了很大很大的压力,虚拟机开发团队注意到,大部分应用共享数据状态只会持续很短的一段时间,为了这段时间去挂起和恢复线程并不值得。所以自旋锁就是线程获取锁失败,不会进入阻塞状态,而是让线程执行一个忙循环(自旋)自旋的默认次数是10次。

自适应自旋锁:

自旋等待虽然避免了线程切换的开销,但是它仍要占用处理器时间的,因此如果锁被占用的时间很短,自旋等待效果就会非常好,反正如果锁占用的时间很长会白白浪费资源。

JDK6之后引入了自适应自旋锁自旋的时间不再固定,而是由前一次在同一个锁上的自旋时间以及锁的拥有者的状态决定的,如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次等待可能会再次成功,进而将运行等待持续时间相对更长一点,反之如果这个自旋很少成功,那么以后获得这个锁时将可能省略掉自旋以避免白白浪费时间。

2.锁消除

锁消除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。

3.锁粗化

原则上来说,锁的粒度越细越好,这样能提高并发的性能,但是如果有在一个代码块中有一系列的锁,那么久有多次的加锁和解锁,甚至加锁解锁是出现在循环体中,那即使没有线程竞争,频繁的进行互斥同步操作也会导致不必要的性能损耗。所有有时候锁粗化反而会提高性能。

4.轻量级锁

在代码进入同步块的时候,如果此同步对象没有被锁定,虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间。用于存储
锁对象目前的MarkWord的拷贝。

然后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向LockRecord的指针,如果这个更新成功了,那么这个线程就拥有了改对象的锁。 并且对象MarkWord的锁标志位将变为00即表示对象处于轻量级锁定状态

如果更新失败了,虚拟机首先会检查对象的MarkWord是否已经指向虚拟机的当前栈帧,如果有,则说明该当前线程已经持有了改对象的锁 那么久可以进入同步快继续执行否则说明这个锁对象已经被其他线程抢占了
如果两个以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁,锁标志的状态值变为10

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

5.偏向锁

偏向锁的目的是消除数据在无竞争情况下的同步原语。如果说轻量级锁是在无竞争的情况下把整个同步都消除,连CAS操作都不做了。

偏向锁的意思是锁会偏向于第一个获得它的线程,如果接下来的执行过程中,该线程没有被其他线程获取,则持有偏向锁的线程永远不需要再进行同步。

当对象第一次被线程获取的时候,虚拟机将会把对象头中的标志位设为01,即偏向模式,同时使用CAS操作把获取到这个锁的线程的ID记录在对象的MarkWord中,如果CAS成功则持有偏向锁的线程以后进入这个锁相关的同步块时,虚拟机都可以不再进行仍和同步操作 当另一个线程去尝试获取这个锁时3,偏向模式就结束

参考资料
《深入理解Java虚拟机 JVM高级特性与最佳实践》
https://www.jianshu.com/p/36eedeb3f912http://ifeve.com/java-synchronized/轻量级锁/