bigywater.tech
Java · 155

虚拟线程 Pinning:什么情况下仍然会卡住载体线程

虚拟线程什么时候仍然会卡住载体线程?这篇限制载体线程数,用同样的阻塞任务对比无锁、ReentrantLock 和 synchronized,并在 JDK 21 与 27 上各跑一遍(虚拟线程的基本行为见上一篇)。

2548 vs 520 ms
JDK 21:synchronized 里阻塞与无锁的耗时(载体线程 2 个)
519 ms
JDK 27 上 synchronized 里阻塞的耗时
reason:MONITOR
tracePinnedThreads 里固定的原因

JDK 21 的固定

实测 · 本机执行输出
  [没有锁]  plain:10 个虚拟线程各阻塞 500 ms,总耗时 520 ms
  [ReentrantLock 里]  lock:10 个虚拟线程各阻塞 500 ms,总耗时 519 ms
  [synchronized 里]  sync:10 个虚拟线程各阻塞 500 ms,总耗时 2548 ms

JDK 27

实测 · 本机执行输出
  [没有锁]  plain:10 个虚拟线程各阻塞 500 ms,总耗时 519 ms
  [ReentrantLock 里]  lock:10 个虚拟线程各阻塞 500 ms,总耗时 518 ms
  [synchronized 里]  sync:10 个虚拟线程各阻塞 500 ms,总耗时 519 ms

tracePinnedThreads

实测 · 本机执行输出
  VirtualThread[#N]/runnable@ForkJoinPool-1-worker-K reason:MONITOR
      java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:199)
      java.base/jdk.internal.vm.Continuation.onPinned0(Continuation.java:393)
      java.base/java.lang.VirtualThread.parkNanos(VirtualThread.java:635)
      java.base/java.lang.VirtualThread.sleepNanos(VirtualThread.java:807)
      java.base/java.lang.Thread.sleep(Thread.java:507)
      Main.lambda$main$0(Main.java:1) <== monitors:1
      java.base/java.lang.VirtualThread.run(VirtualThread.java:329)
  (JDK 27 同一程序、同一参数的输出:) ''

分步演示

虚拟线程固定
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12 与 27;载体线程数用 -Djdk.virtualThreadScheduler.parallelism=2、maxPoolSize=2 限制
    • 没有验证:JDK 22 到 26 之间固定行为是在哪个版本改变的、native 方法与 Foreign 调用造成的固定、Object.wait() 在 synchronized 里的行为、类初始化期间的固定、真实竞争下 synchronized 的表现
    京ICP备2026067502号-1京公网安备11010502063487号