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

Java 22.0.2虚拟线程高负载下调用DatagramSocket.receive永久挂起

虚拟线程池高负载下卡顿问题排查

线程池配置

使用如下代码创建虚拟线程池:

private final ScheduledExecutorService serverExecutor2 = Executors.newScheduledThreadPool(2000, Thread.ofVirtual().name("COAP-SERVER2-", 0).factory());

卡顿现象

高负载状态下线程池出现卡顿,状态信息显示:

serverExecutor2=@ScheduledThreadPoolExecutor[java.util.concurrent.ScheduledThreadPoolExecutor@327e5be5[Running, pool size = 2000, active threads = 0, queued tasks = 60000, completed tasks = 97847]]

虚拟线程状态

所有虚拟线程均处于parking状态,栈信息如下:

#75 "COAP-SERVER2-5" virtual
      java.base/java.lang.VirtualThread.park(VirtualThread.java:592)
      java.base/java.lang.System$2.parkVirtualThread(System.java:2639)
      java.base/jdk.internal.misc.VirtualThreads.park(VirtualThreads.java:54)
      java.base/java.util.concurrent.locks.LockSupport.park(LockSupport.java:369)
      java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:519)
      java.base/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3780)
      java.base/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3725)
      java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1707)
      java.base/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1177)
      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.VirtualThread.run(VirtualThread.java:311)

VirtualThread-unparker阻塞问题

问题根源指向VirtualThread-unparker线程阻塞,其队列堆积大量等待任务,线程栈信息:

"VirtualThread-unparker" #92 [593799] daemon prio=5 os_prio=0 cpu=2238.28ms elapsed=373.27s tid=0x00007f1b3002fd50 nid=593799 waiting on condition  [0x00007f1e6db43000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at jdk.internal.misc.Unsafe.park(java.base@22.0.2/Native Method)
        - parking to wait for  <0x00001000177791b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(java.base@22.0.2/LockSupport.java:269)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(java.base@22.0.2/AbstractQueuedSynchronizer.java:1758)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@22.0.2/ScheduledThreadPoolExecutor.java:1182)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@22.0.2/ScheduledThreadPoolExecutor.java:899)
        at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@22.0.2/ThreadPoolExecutor.java:1070)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@22.0.2/ThreadPoolExecutor.java:1130)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@22.0.2/ThreadPoolExecutor.java:642)
        at java.lang.Thread.runWith(java.base@22.0.2/Thread.java:1583)
        at java.lang.Thread.run(java.base@22.0.2/Thread.java:1570)
        at jdk.internal.misc.InnocuousThread.run(java.base@22.0.2/InnocuousThread.java:186)

   Locked ownable synchronizers:
        - None

调试发现任务时间异常

通过Arthas调试发现,unparker队列头部的任务本应早已执行,但未被处理:

[arthas@593599]$ ognl '@java.lang.VirtualThread@UNPARKER.toString()'
@String[java.util.concurrent.ScheduledThreadPoolExecutor@154b1210[Running, pool size = 1, active threads = 0, queued tasks = 30027, completed tasks = 413674]]
[arthas@593599]$ ognl '@System@nanoTime()'
@Long[84707647860354]
[arthas@593599]$ ognl '@java.lang.VirtualThread@UNPARKER.queue.peek()'
@ScheduledFutureTask[
    sequenceNumber=@Long[1227676],
    time=**@Long[84137649857516]**,
    period=@Long[0],
    outerTask=@ScheduledFutureTask[java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@5d021eb6[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@7d5f12fb[Wrapped task = java.lang.VirtualThread$$Lambda/0x00007f1bf357cc70@56d5ca23]]],
    heapIndex=@Integer[0],
    this$0=@ScheduledThreadPoolExecutor[java.util.concurrent.ScheduledThreadPoolExecutor@154b1210[Running, pool size = 1, active threads = 0, queued tasks = 30027, completed tasks = 413674]],
    state=@Integer[0],
    NEW=@Integer[0],
    COMPLETING=@Integer[1],
    NORMAL=@Integer[2],
    EXCEPTIONAL=@Integer[3],
    CANCELLED=@Integer[4],
    INTERRUPTING=@Integer[5],
    INTERRUPTED=@Integer[6],
    callable=@RunnableAdapter[java.util.concurrent.Executors$RunnableAdapter@7d5f12fb[Wrapped task = java.lang.VirtualThread$$Lambda/0x00007f1bf357cc70@56d5ca23]],
    outcome=null,
    runner=null,
    waiters=null,
    STATE=@FieldInstanceReadWrite[VarHandle[varType=int, coord=[class java.util.concurrent.FutureTask]]],
    RUNNER=@FieldInstanceReadWrite[VarHandle[varType=java.lang.Thread, coord=[class java.util.concurrent.FutureTask]]],
    WAITERS=@FieldInstanceReadWrite[VarHandle[varType=java.util.concurrent.FutureTask$WaitNode, coord=[class java.util.concurrent.FutureTask]]],

当前系统时间为84707647860354,但队列头部任务的time值为84137649857516,远早于当前时间却未被执行。

疑问

是使用方式有误,还是JDK或操作系统存在Bug?


更新:发现DatagramChannel触发的时间溢出问题

进一步排查发现,当调用DatagramSocket.receive()时会触发时间计算溢出:

ts=2024-08-06 14:32:36;thread_name=ForkJoinPool-1-worker-1;id=97;is_daemon=true;priority=5;TCCL=jdk.internal.loader.ClassLoaders$AppClassLoader@5c647e05
    @java.util.concurrent.ScheduledThreadPoolExecutor.triggerTime() -- get a number close to Long.MAX_VALUE as param and output nagative number.
        at java.util.concurrent.ScheduledThreadPoolExecutor.schedule(ScheduledThreadPoolExecutor.java:560)
        at java.lang.VirtualThread.scheduleUnpark(VirtualThread.java:705)
        at java.lang.VirtualThread.parkNanos(VirtualThread.java:632)
        at java.lang.System$2.parkVirtualThread(System.java:2652)
        at jdk.internal.misc.VirtualThreads.park(VirtualThreads.java:67)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:408)
        at sun.nio.ch.Poller.pollIndirect(Poller.java:137)
        at sun.nio.ch.Poller.poll(Poller.java:102)
        at sun.nio.ch.Poller.poll(Poller.java:87)
        at sun.nio.ch.DatagramChannelImpl.park(DatagramChannelImpl.java:494)
        at sun.nio.ch.DatagramChannelImpl.tryBlockingReceive(DatagramChannelImpl.java:762)
        at sun.nio.ch.DatagramChannelImpl.blockingReceive(DatagramChannelImpl.java:692)   ---- if nanos is zero, nanos = Long.MAX_VALUE, which caused overflow at ScheduledThreadPoolExecutor.schedule 
        at sun.nio.ch.DatagramSocketAdaptor.receive(DatagramSocketAdaptor.java:204)
        at java.net.DatagramSocket.receive(DatagramSocket.java:714)

当接收超时时间为0时,底层会将nanos设置为Long.MAX_VALUE,导致ScheduledThreadPoolExecutor.schedule()计算triggerTime时发生数值溢出,得到负数,进而导致unparker队列中的任务无法被正确调度。

内容的提问来源于stack exchange,提问作者Nick Allen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:14:53