概述
在上篇博客中,我们提到轻量级锁、偏向锁、重量级锁等概念。在早期的 java 虚拟机中,synchronized 锁基于 monitor 管程对象实现,而 monitor 对象又基于底层操作系统互斥量来保证同步。这就意味着,所有线程切换时需要从 用户态 转化为 核心态,而线程的转化过程比较缓慢,这也是早期 synchronized 锁效率低下的主要原因。在 jdk6 之后,jvm 对 syncrhonized 锁进行了一系列优化。本篇博客我们就来整理一下 jvm 都对 synchronized 锁进行了哪些优化。
JVM 对 Synchronized 的优化
本篇博客分以下六个模块展开:
- 偏向锁
- 轻量级锁
- 锁转化关系图
- 自旋锁
- 锁消除
- 锁粗化
1、偏向锁
偏向锁是 jdk6 新引入的一种锁优化。其中它的“偏”就是指偏向某个线程。翻译过来也就是说,当某个线程被锁 偏向 后:在后序的执行过程中,如果没有其他线程获取该锁,那么锁对象永远偏向该线程,当该线程获取偏向锁时,无须进行任何同步操作。
也就是说,偏向锁优化的原理就是消除数据在无竞争情况下的同步操作,进而提高效率。
一般情况下,偏向锁总是偏向第一次获取锁的线程。当锁对象第一次被线程获取后,虚拟机将该同步对象 Mark Word 区域的锁标识设置为“01”,即偏向模式,同时使用 CAS 将获取锁的线程 ID 保存到 Mark Word 之中。如果设置成功,后序该线程获取锁对象时,无须进行任何同步操作。
当另一个线程尝试获取锁资源时,偏向模式宣告结束。
-
如果当前锁对象处于锁定状态,通过 CAS 将该锁标识置位“00”,即升级为“轻量级锁”。
-
如果当前锁对象处于未锁定状态,则撤销偏向,将偏向标识置位0,即非偏向锁阶段。
偏向锁可以提高同步、但无竞争的程序性能。如果程序中锁总是被不同的线程获取,那偏向模式是多余的,如果程序中的锁总是被某一个线程获取,那它可以大幅提高程序性能。
2、轻量级锁
轻量级锁是 JDK6 中引入的新型锁机制。它的本意不是为了替代重量级锁,而是为了在没有多线程竞争的场景下,减少重量级锁使用操作系统互斥量产生的性能损耗。
和重量级锁相同,轻量级锁也基于 HotSpot 虚拟机对象头的 Mark Word 模块实现。之前提到锁标识为“10” 时表示当前锁为重量级锁,而轻量级锁的锁标识为“00”。
下面我简单描述一下轻量级锁的加锁过程:
-
在代码进入同步块时,如果当前同步对象还没有被 锁定