简述 Java 锁升级的机制
Synchronized
一直被称为重量级锁。但是在JDK 1.6之后它已经变得不那么重了。JDK 1.6 对Synchronized
的优化点在于:
引入了偏向锁
引入了轻量级锁
在JDK 1.6 中,Synchronized
锁有四种状态,级别从低到高依次是:无锁、偏向锁、轻量级锁、重量级锁。
这几个状态会随着锁竞争升级,但是不可以降级。
# 偏向锁
为什么引入偏向锁?
不存锁竞争,或者总是由同一线程多次获得锁的场景,偏向锁的代价更低。
当一个线程访问同步块并获取到锁时,在锁对象头记录该线程的id,以后该线程进入和退出该同步块时不需要CAS来加锁和解锁。
偏向锁何时释放?
偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程是不会主动释放偏向锁的。
偏向锁一定起到正面作用吗?
不是的。
偏向锁的适用场景是:不存锁竞争,或者总是由同一线程多次获得锁的场景。
如果你确定你的程序中 锁通常处于竞争状态,可以通过JVM参数关闭偏向锁。关闭后,程序回魔人进入轻量级锁状态。
-XX:UseBiasedLocking=false
2
3
# 轻量级锁
轻量级锁是指当锁是偏向锁的时候,却被另外的线程所访问,此时偏向锁就会升级为轻量级锁,其他线程会通过自旋(关于自旋的介绍见文末)的形式尝试获取锁,线程不会阻塞,从而提高性能。
轻量级锁的获取主要由两种情况:① 当关闭偏向锁功能时;② 由于多个线程竞争偏向锁导致偏向锁升级为轻量级锁。
轻量级锁何时升级为重量级锁?
若当前只有一个等待线程,则该线程将通过自旋进行等待。但是当自旋超过一定的次数时,轻量级锁便会升级为重量级锁(锁膨胀)。
另外,当一个线程已持有锁,另一个线程在自旋,而此时又有第三个线程来访时,轻量级锁也会升级为重量级锁(锁膨胀)。
# 重量级锁
重量级锁是指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。
重量级锁的获取是释放一般会有线程上下文切换,代价是比较大的,所以说是重量级锁。