为什么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周瑜,里面有更多干货文章。

相关推荐
这里有鱼汤2 小时前
发现一个高性能回测框架,Python + Rust,比 backtrader 快 250 倍?小团队必备!
后端·python
一水鉴天2 小时前
整体设计 之 绪 思维导图引擎 之 引 认知系统 之 引 认知系统 之 序 认知元架构 之 元宇宙:三种“即是”逻辑与数据安全措施的适配(豆包助手 之10)
架构·认知科学
程序员爱钓鱼2 小时前
Go语言实战案例 — 项目实战篇:图书管理系统(文件存储)
后端·google·go
元闰子3 小时前
OLTP上云,哪种架构最划算?·VLDB'25
数据库·后端·云原生
虫小宝3 小时前
淘宝客app的API网关设计:认证授权与流量控制策略
java·分布式·架构
IT_陈寒3 小时前
Vite 5.0重磅升级:8个性能优化秘诀让你的构建速度飙升200%!🚀
前端·人工智能·后端
努力努力再努力wz3 小时前
【c++进阶系列】:map和set的模拟实现(附模拟实现的源码)
java·linux·运维·开发语言·c++
hui函数3 小时前
scrapy框架-day02
后端·爬虫·python·scrapy
Moshow郑锴3 小时前
SpringBootCodeGenerator使用JSqlParser解析DDL CREATE SQL 语句
spring boot·后端·sql