锁的状态总共有四种:无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁(但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级)。锁的状态是通过对象监视器在对象头中的字段来表明的。JDK 1.6中默认是开启偏向锁和轻量级锁的。
- 锁膨胀:从轻量锁膨胀到重量级锁是在轻量级锁解锁过程发生的。
四种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级。
1.无锁状态
2.偏向锁状态
3.轻量级锁状态
4.重量级锁状态
偏向锁
偏向锁:一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。
如果需要,使用参数-XX:-UseBiasedLocking禁止偏向锁优化(默认打开)
轻量级
轻量级锁:当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
“轻量级”是相对于使用操作系统互斥量来实现的传统锁而言的。但是,轻量级锁并不代替重量级锁的,其本意是在没有多线程竞争的前提下,减少传统的重量级锁使用产生的性能消耗。
在解释轻量级锁的执行过程之前,先明白一点,轻量级锁所适应的场景是线程交替执行同步块的情况,如果存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁。
重量级锁
重量级锁:当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。
- 锁的升级过程:
一旦对象锁升级为重级锁后,后续线程对该对象的操作都将是加锁为重量级锁 - 锁不存在降级:
锁只有从偏向锁->轻量级/重量级 或者 直接 轻量级-> 重量级. 不会降级,只有解锁
重量级锁是通过monitor实现的,锁的标志位为10,对象头中的指针指向monitor对象的起始地址。在java虚拟机中,monitor是由ObjectMonitor实现。位于\openjdk-jdk8u-jdk8u\openjdk-jdk8u-jdk8u\hotspot\src\share\vm\runtime包中。
Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的。而操作系统实现线程之间的切换这就需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么Synchronized效率低的原因。因此,这种依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。