syncronized锁升级的过程
无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁
锁升级的过程是指锁从较低级别的锁(如偏向锁)升级到较高级别的锁(如轻量级锁或重量级锁)的过程。锁升级是为了更好地适应不同级别的并发压力,从而提高程序的性能。下面是锁升级的过程概述:
锁升级的过程
无锁状态:初始状态下,对象没有任何锁标志。
偏向锁:当第一个线程获取锁时,锁变为偏向锁状态。此时,锁只属于这个线程。
轻量级锁:当第二个线程尝试获取锁时,由于第一个线程持有锁还没有释放,偏向锁失效,锁升级为轻量级锁。此时,第二个线程将尝试通过CAS 操作获取锁,如果第二个线程获取锁成功,此时的锁还是轻量级锁。在第二个线程持有锁的时候,如果线程一也尝试获取锁,那么也需要通过CAS 操作获取锁。
重量级锁:如果轻量级锁的 CAS 失败多次,或者轻量级锁自旋超过一定次数仍未获取到锁,则锁升级为重量级锁。
锁升级的具体步骤:
无锁状态:初始状态下,对象没有任何锁标志。在 Java 中,每个对象都有一个锁标志位,用于表示当前的锁状态。
偏向锁:当第一个线程获取锁时,锁标志位被设置为偏向锁状态。JVM 会记录下持有锁的线程 ID。只要该线程一直持有锁,就不需要进行任何额外的同步操作。
轻量级锁:当第二个线程尝试获取锁时,偏向锁失效。线程尝试通过 CAS 操作获取锁。如果 CAS 成功,则线程获得了锁。如果 CAS 失败,线程会尝试自旋一段时间以获取锁。如果自旋成功,则获取锁;如果自旋失败,则锁升级为重量级锁。
重量级锁:如果轻量级锁的 CAS 失败多次,或者轻量级锁自旋超过一定次数仍未获取到锁,则锁升级为重量级锁。
重量级锁会导致线程阻塞,直到锁被释放。
重量级锁的获取和释放涉及到操作系统级别的互斥锁。
示例代码
下面是一个简单的示例代码,演示锁升级的过程:
public class LockUpgradeExample {
public static void main(String[] args) {
Test test = new Test();
// 创建两个线程
Thread t1 = new Thread(() -> {
synchronized (test) {
System.out.println("Thread 1 acquired lock.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Thread 1 released lock.");
}
}, "Thread-1");
Thread t2 = new Thread(() -> {
synchronized (test) {
System.out.println("Thread 2 acquired lock.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Thread 2 released lock.");
}
}, "Thread-2");
t1.start();
t2.start();
}
static class Test {}
}
分析
在这个示例中,Thread-1 和 Thread-2 交替获取锁。当 Thread-1 获取锁时,锁最初可能是偏向锁状态。当 Thread-2 尝试获取锁时,偏向锁失效,锁升级为轻量级锁。如果 Thread-2 通过 CAS 操作尝试获取锁多次失败,或者自旋时间过长仍未能获取到锁,那么轻量级锁会升级为重量级锁。,此时 Thread-2 线程变成阻塞状态。
总结
锁升级的过程是从无锁状态到偏向锁,再到轻量级锁,最后升级为重量级锁。这种机制有助于减少锁的开销,并提高程序的性能。在大多数情况下,锁会尽量保持在较低级别的状态,只有在竞争激烈的情况下才会升级到更高级别