为什么Spring 6中要把synchronized替换为ReentrantLock?

作为一名资深Spring爱好者,没事看看Spring的commit记录是一大爱好,这不,刚刚看了一下Spring最新的commit记录,其中有一条是这样的:

5天前提交的,标题意思是:为了避免thread pinning,所以修改了一些类中的代码,那具体修改了什么呢?我把重点给大家圈出来了:

代码中的writeLock定义为:

所以改动很明显了,就是去掉了synchronized,替换成为ReentrantLock,问题来了,为什么要这么做呢,synchronized不好用了?

我们先回到commit的标题:

我们需要解决3个问题:

1、什么是thread pinning?

2、为什么要避免thread pinning?

3、为什么把synchronized替换成ReentrantLock就可以避免thread pinning?

什么是thread pinning?

所谓thread pinning,就是线程绑定,有两种理解。

第一种,我们知道线程是在cpu上运行的,如果是多核cpu,那么同一个线程就可能一下是a核上运行,一下在b核上运行,而所谓线程绑定,就是把某一个线程固定在某个cpu核上运行。

第二种,跟虚拟线程有关,虚拟线程是JVM层面自己实现的,并不是真正的操作系统线程,并且虚拟线程是需要基于操作系统线程来运行的,因此虚拟线程和操作系统线程之间也存在绑定关系,正常情况下,一个虚拟线程可以运行在不同的操作系统线程之上,但是如果发生了thread pinning,那么就表示一个虚拟线程和一个操作系统线程绑定了,两者同生同死,那就不太好了。

而本文要分析的就是第二种情况,或者说这个commit要解决的就是第二种情况。

为什么synchronized会导致thread pinning?

当一个虚拟线程在获取锁时,如果获取不到,那么虚拟线程自身进行等待就可以了,可以把底层的操作系统线程释放掉,让它去服务其他的虚拟线程,没必要虚拟线程自己要等待,还要拉着底层操作系统线程一起等待。

但是当一个虚拟线程在执行某个加了synchronized关键字的方法时,糟糕的情况就出现了,这就会导致虚拟线程对应的底层操作系统线程要一起进行等待,从而占用了底层操作系统线程的资源,这本质上是"历史包袱",还需要给JVM底层来进行优化,因此,目前的解决方式就是使用ReentrantLock。

为什么ReentrantLock会避免thread pinning?

当一个虚拟线程在调用ReentrantLock的lock()方法进行加锁时,底层最终会调用LockSupport中的park()方法,而在这个方法中就对虚拟线程进行判断:

很明显,如果是虚拟线程就会单独进行处理,特别要注意的是,如果是虚拟线程,就不会进图中的else逻辑,也就不会对底层操作系统线程进行park,也就不会让底层操作系统线程进行等待。

VirtualThreads.park()最终会调用VirtualThread中的park():

然后调用:

然后调用:

这里似乎就是通过一个循环在进行等待?这块代码还没有深入研究,只能先这么理解了。

总之,ReentrantLock本质上就是对虚拟线程单独进行了优化,所以在加锁时,只需要虚拟线程自己等待就可以了,底层操作系统线程可以去干别的,这样就能提高底层操作系统线程的利用率。

再看一眼最开始的commit记录:

我总算知道Spring大佬为什么要避免thread pinning了,总算知道为什么要把synchronized替换成ReentrantLock了,原来是为了虚拟线程啊,赞!

我是IT周瑜,深耕Spring全家桶多年,欢迎关注我的个人公众号:IT周瑜,里面有更多干货文章。

相关推荐
better_liang9 小时前
每日Java面试场景题知识点之-XXL-JOB分布式任务调度实践
java·spring boot·xxl-job·分布式任务调度·企业级开发
会游泳的石头9 小时前
一行注解防死循环:MyBatis 递归深度限制(无需 level 字段)
java·mybatis
q***o3769 小时前
Spring Boot环境配置
java·spring boot·后端
hhzz9 小时前
Springboot项目中使用POI操作Excel(详细教程系列3/3)
spring boot·后端·excel·poi·easypoi
oMcLin9 小时前
如何在SUSE Linux Enterprise Server 15 SP4上通过配置并优化ZFS存储池,提升文件存储与数据备份的效率?
java·linux·运维
TaiKuLaHa9 小时前
Spring Bean的生命周期
java·后端·spring
刀法如飞10 小时前
开箱即用的 DDD(领域驱动设计)工程脚手架,基于 Spring Boot 4.0.1 和 Java 21
java·spring boot·mysql·spring·设计模式·intellij-idea
我是苏苏10 小时前
Web开发:C#通过ProcessStartInfo动态调用执行Python脚本
java·服务器·前端
JavaGuide10 小时前
SpringBoot 官宣停止维护 3.2.x~3.4.x!
java·后端