虚拟线程

JDK 19初次引入预览版虚拟线程(Virtual Thread),并在JDK 21中正式发布,线程转储(thread dump)可以用于虚拟线程问题排查。由于虚拟线程可能有数千或者数百万个,常规的jstack并不适用,目前有如下方式生成包含虚拟线程信息的线程转储:

jcmd <pid> Thread.dump_to_file -format=json <file>
jcmd <pid> Thread.dump_to_file -format=text <file>

第一种格式示例如下:

{
  "threadDump": {
    "processId": "48390",
    "time": "2023-11-01T02:53:36.881597814Z",
    "runtimeVersion": "22-internal",
    "threadContainers": [
      {
        "container": "java.util.concurrent.ThreadPerTaskExecutor@672fb5f8",
        "parent": "<root>",
        "owner": null,
        "threads": [
          {
            "tid": "36",
            "name": "",
            "stack": [
              "java.base\/java.lang.VirtualThread.parkNanos(VirtualThread.java:624)",
              "java.base\/java.lang.VirtualThread.sleepNanos(VirtualThread.java:795)",
              "java.base\/java.lang.Thread.sleepNanos(Thread.java:489)",
              "java.base\/java.lang.Thread.sleep(Thread.java:522)",
              "Test.lambda$simple$1(Test.java:16)",
              "java.base\/java.util.concurrent.FutureTask.run(FutureTask.java:317)",
              "java.base\/java.lang.VirtualThread.run(VirtualThread.java:318)"
            ]
          }
        ],
        "threadCount": "1"
      }
      ...
    ]
  }
}

第二种格式示例如下:

#38 "VirtualThread-unparker"
      java.base/jdk.internal.misc.Unsafe.park(Native Method)
      java.base/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:269)
      java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1758)
      java.base/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1182)
      java.base/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899)
      java.base/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1070)
      java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
      java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
      java.base/java.lang.Thread.run(Thread.java:1570)
      java.base/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:186)

#36 "" virtual
      java.base/java.lang.VirtualThread.parkNanos(VirtualThread.java:624)
      java.base/java.lang.VirtualThread.sleepNanos(VirtualThread.java:795)
      java.base/java.lang.Thread.sleepNanos(Thread.java:489)
      java.base/java.lang.Thread.sleep(Thread.java:522)
      Test.lambda$simple$1(Test.java:16)
      java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
      java.base/java.lang.VirtualThread.run(VirtualThread.java:318)
...

新的线程转储格式不包括对象地址、锁、JNI 统计信息、堆统计信息以及传统线程转储中出现的其他信息。ATP已经支持如上命令生成的线程转储,对应的功能示例如下:

image

image