当 Java 的 synchronized 升级到重量级锁后,所有线程都释放锁了,此时它还是重量级锁吗?
当 Java 的 synchronized 升级到重量级锁后,所有线程都释放锁了,此时它还是重量级锁吗?
回答重点
当重量级锁释放了之后,锁对象是无锁的。
有新的线程来竞争的话又会从轻量级锁开始。
扩展知识
我们都知道 synchronized 的锁升级,也听过锁升级之后不会降级,所以理所当然的认为当一个锁升级为重量级锁之后,任何线程再来争抢之后会走重量级锁的逻辑。
不会再从无锁到偏向锁到轻量级锁再到重量级锁。
那事实是怎样的呢?这篇咱们不看源码,直接整结果。
我们直接看锁对象的锁标志来判断。
直接上实验代码。
代码非常简单,先看下无锁的对象布局,然后多线程争抢此时应该是重量级锁,然后 sleep 等待所有线程执行完毕释放锁,然后再看看此时的锁布局。
最后再加一次锁看看对象布局。
这里有个注意点
1.8 的偏向锁是会延迟生效的,得在 JVM 启动 4 秒后生效,通过 -XX:BiasedLockingStartupDelay=0关闭偏向锁延迟
这边我没搞这个参数,因为不是重点,所以等下结果里面不会有偏向锁。
上结果!
结果显而易见,初始是无锁的。
然后4个线程同时竞争变成了重量级锁。
4个线程执行完毕之后,锁对象变成了无锁。
此时再有一个线程去争抢锁,就从无锁变成了轻量级锁。
所以当重量级锁释放了之后,锁对象是无锁的!
有新的线程来竞争的话又会从轻量级锁开始!
最后
想要自己测试的话,引用一个 jol 的包即可
1 2 3 4 5
| <dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.14</version> </dependency>
|
代码也直接拷给你们:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class YesLockTest {
static Object yesLock;
public static void main(String[] args) throws InterruptedException { yesLock = new Object(); System.out.println("无锁时对象布局:" + ClassLayout.parseInstance(yesLock).toPrintable()); IntStream.rangeClosed(1,4).forEach(i->{getYesLock();}); Thread.sleep(5000L); System.out.println("无竞争之后,此时的对象布局:" + ClassLayout.parseInstance(yesLock).toPrintable()); getYesLock(); }
private static void getYesLock() { new Thread(() -> { try { synchronized (yesLock) { System.out.println("线程[" + Thread.currentThread().getName() + "]" + ":重量级锁状态对象布局:" + ClassLayout.parseInstance(yesLock).toPrintable()); } } catch (Exception e) { e.printStackTrace(); } }).start(); }
}
|