JDK 21虚拟线程固定无法复现,为何MySQL并发未达预期?
虚拟线程与MySQL驱动的线程固定问题
一、虚拟线程的线程固定特性
JDK 21官方文档明确指出:虚拟线程(VT)进入synchronized代码块/方法、调用本地方法时,会触发「线程固定」——此时虚拟线程会绑定到某一个平台线程(即载体线程)上,直到退出synchronized代码块或完成本地方法调用,期间无法被JVM调度切换到其他载体线程。
二、MySQL驱动的线程固定现象
有开发者提出疑问:使用JDK虚拟线程时,9.0.0之前的MySQL驱动(比如8.4版本)无法让虚拟线程按预期并行处理数据库语句,并发能力未得到提升。
三、线程固定的复现测试
为验证该现象,开发者设计了测试场景:创建12个任务,每个任务在synchronized代码块内执行3次1000ms的阻塞操作。
- 若用平台线程执行,每个任务独立运行,耗时3秒;
- 若虚拟线程被固定,在仅提供4个载体线程的情况下,12个任务需分3批执行,总耗时应达9秒。
但首次测试结果超出预期:12个任务几乎同时在3秒内完成,期间JVM甚至创建了14个载体线程。开发者最初未能复现线程固定,后续才找到正确的复现方式。
四、旧版驱动问题与新版修复
旧版MySQL驱动8.4的问题根源
旧版驱动的核心逻辑(比如连接池管理、SQL语句执行的关键流程)中,大量使用了synchronized块来保证线程安全,或是在阻塞IO操作前后调用了本地方法。当虚拟线程进入这些代码段时,会被固定到载体线程上;当大量虚拟线程同时执行这类操作时,载体线程会被占满,无法调度其他虚拟线程,最终导致并发能力下降,和使用平台线程的效果无异。
9.0.x版本的修复方式
9.0.x版本的驱动主要做了两方面优化:
- 将原有的
synchronized同步逻辑替换为java.util.concurrent.locks包下的锁实现(比如ReentrantLock),避免触发虚拟线程的线程固定; - 重构了本地方法调用的时机,确保虚拟线程在执行数据库阻塞IO前,先退出可能导致线程固定的代码段,让JVM可以正常调度虚拟线程,提升并发利用率。
五、JDK的后续优化
Java 24将对synchronized代码块和方法进行改进,让虚拟线程进入这类同步代码时不再被绑定到载体线程,从JVM层面解决synchronized导致的线程固定问题。
内容的提问来源于stack exchange,提问作者user2023577
相关产品推荐
相关产品推荐

