1.概述
Java内置锁的状态总共有4种状态,级别由低到高依次为:无锁、偏向锁、轻量级锁和重量级锁。其实在JDK 1.6之前,Java内置锁还是一个重量级锁,是一个效率比较低下的锁,在JDK 1.6之后,JVM为了提高锁的获取与释放效率,对synchronized的实现进行了优化,引入了偏向锁和轻量级锁,从此以后Java内置锁的状态就有了4种(无锁、偏向锁、轻量级锁和重量级锁),并且4种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级,也就是说只能进行锁升级(从低级别到高级别)
2.锁升级演变过程
如下图,为在锁升级过程,对象头的markWord状态位的值含义。
- 无锁:锁对象刚创建的时候,处于无锁状态,是否为偏向锁位置为0,锁标志位为01。
- 偏向锁线程获取到该锁,此时是否为偏向锁标志位为1,锁标志位为01(偏向锁可认为是无锁)。右边54位记录线程id,当锁处于偏向锁的时候。如果有另一个锁试图获取锁,则偏向锁就会升级为轻量级锁。
- 偏向锁撤销条件:1)多个线程抢夺锁资源,导致锁升级。2)调用锁对象的hashCode方法或者System.identityHashCode()方法 - 轻量级锁,多个线程抢到锁资源,锁标志位为00,当线程自旋多次之后,仍然无法获取到锁资源,锁对象就会升级为重量级锁。持有锁的线程会在栈帧中创建一个lockRecord区域,用来存储markWrod对象信息
- 重量级锁:锁状态标志位为00,采用系统内核的互斥锁实现。
2.1 不同状态下的markWord
2.1.1 32位虚拟机
2.1.1 64位虚拟机
- lock:锁状态标记位,占两个二进制位,由于希望用尽可能少的二进制位表示尽可能多的信息,因此设置了lock标记。该标记的值不同,整个Mark Word表示的含义就不同。
- biased_lock:对象是否启用偏向锁标记,只占1个二进制位。为1时表示对象启用偏向锁,为0时表示对象没有偏向锁
- age:4位的Java对象分代年龄。在GC中,对象在Survivor区复制一次,年龄就增加1。当对象达到设定的阈值时,将会晋升到老年代。默认情况下,并行GC的年龄阈值为15,并发GC的年龄阈值为6。由于age只有4位,因此最大值为15,这就是-XX:MaxTenuringThreshold选项最大值为15的原因
- identity_hashcode:31位的对象标识HashCode(哈希码)采用延迟加载技术,当调用Object.hashCode()方法或者System.identityHashCode()方法计算对象的HashCode后,其结果将被写到该对象头中。当对象被锁定时,该值会移动到Monitor(监视器)中
- thread:54位的线程ID值为持有偏向锁的线程ID
- ptr_to_lock_record:占62位,在轻量级锁的状态下指向栈帧中锁记录的指针。
- ptr_to_heavyweight_monitor:占62位,在重量级锁的状态下指向对象监视器的指针