写点什么

Synchronized 升级成重量级锁之后就下不来了?你错了!

发布于: 2021 年 03 月 03 日
Synchronized升级成重量级锁之后就下不来了?你错了!

你好,我是 yes。


昨天的一篇关于 Synchronized 的一个点,网上99%的文章都错了发了之后有很多读者私聊我,感觉打破了轻量级锁升级的一个认知。


然后有一位读者的留言倒是提醒到我还有一个点,关于 Synchronized 的这个点,可能很多人的认识也是错误的


其实以前我的认识也是错误的,直至去年和另一位号主安琪拉讨论的时候才意识到这个问题。


我们都知道 synchronized 的锁升级,也听过锁升级之后不会降级,所以理所当然的认为当一个锁升级为重量级锁之后,任何线程再来争抢之后会走重量级锁的逻辑。


不会再从无锁到偏向锁到轻量级锁再到重量级锁。


那事实是怎样的呢?这篇咱们不看源码,直接整结果。


我们直接看锁对象的锁标志来判断。

直接上实验代码。


代码非常简单,先看下无锁的对象布局,然后多线程争抢此时应该是重量级锁,然后 sleep 等待所有线程执行完毕释放锁,然后再看看此时的锁布局。


最后再加一次锁看看对象布局。


这里有个注意点


1.8 的偏向锁是会延迟生效的,得在 JVM 启动 4 秒后生效,通过 -XX:BiasedLockingStartupDelay=0关闭偏向锁延迟


这边我没搞这个参数,因为不是重点,所以等下结果里面不会有偏向锁。


上结果!



结果显而易见,初始是无锁的。


然后 4 个线程同时竞争变成了重量级锁。


4 个线程执行完毕之后,锁对象变成了无锁


此时再有一个线程去争抢锁,就从无锁变成了轻量级锁


所以当重量级锁释放了之后,锁对象是无锁的!


有新的线程来竞争的话又会从轻量级锁开始!


好了,over。


现在再看 openjdk wiki 上的图,重点关注 unlock,看看是不是很清晰了:



最后

想要自己测试的话,引用一个 jol 的包即可

		<dependency>			<groupId>org.openjdk.jol</groupId>			<artifactId>jol-core</artifactId>			<version>0.14</version>		</dependency>
复制代码

代码也直接拷给你们:


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(); }
}
复制代码



更多内容,欢迎关注我的公众号【yes 的练级攻略】,每周保证至少分享一篇原创技术文。



我是 yes,从一点点到亿点点,欢迎在看、转发、留言,我们下篇见。


发布于: 2021 年 03 月 03 日阅读数: 28
用户头像

分享后端技术干货,驰骋技术的江湖。 2019.01.17 加入

公众号「yes的练级攻略」

评论

发布
暂无评论
Synchronized升级成重量级锁之后就下不来了?你错了!