You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加-Djdk.tracePinnedThreads=full致Spring Boot虚拟线程测试挂起求助

虚拟线程挂起问题分析(带-Djdk.tracePinnedThreads=full参数时)

问题现象

在Spring Boot 3.2.0 + Java 21环境下启用虚拟线程后,添加-Djdk.tracePinnedThreads=full参数时测试会挂起;移除该参数则运行正常。测试逻辑为启动3个虚拟线程调用同步方法testForPin,该方法持有synchronized锁并执行Thread.sleep(1000)。通过jhsdb排查发现无死锁,仅一个虚拟线程持锁处于sleep状态,另外两个虚拟线程阻塞等待锁。

环境配置

  • pom.xml:Spring Boot 3.2.0,指定Java版本21
  • application.properties:已启用虚拟线程,配置应用保持存活
  • 测试代码:3个虚拟线程调用带synchronized修饰的testForPin方法,方法内持有锁并执行Thread.sleep(1000)

原因分析

-Djdk.tracePinnedThreads=full是JVM用于追踪虚拟线程**固定(Pinned)**状态的参数:当虚拟线程持有synchronized这类监视器锁时,会被固定到载体线程(Carrier Thread)上,无法被JVM调度切换。开启full级别追踪时,JVM会在虚拟线程被固定的时机执行大量栈遍历、日志输出操作,这会占用载体线程的大量资源,导致其执行被阻塞,进而让等待锁的其他虚拟线程无法被正常调度,最终表现为测试挂起。

这个问题本质是JVM追踪参数的行为与synchronized锁导致的虚拟线程固定特性冲突,和Spring的核心配置无关,但可以通过调整锁的使用方式来规避。

解决方案与优化建议

  1. 替换锁类型:将synchronized锁替换为java.util.concurrent包中的显式锁(比如ReentrantLock),虚拟线程持有这类锁时不会被固定到载体线程,JVM可以正常调度其他虚拟线程,即使开启-Djdk.tracePinnedThreads=full也不会出现挂起。
  2. 降低追踪级别:如果必须保留synchronized锁,可将参数改为-Djdk.tracePinnedThreads=short,减少日志输出的开销,避免载体线程被阻塞。
  3. Spring配置确认:确保已正确启用虚拟线程(配置spring.threads.virtual.enabled=true),Spring本身无需额外特殊配置来解决该问题,核心优化点在锁的使用和JVM参数调整。

内容的提问来源于stack exchange,提问作者Craig Archer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 16:12:42