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

Zulu OpenJDK21虚拟线程运行数天触发InterruptedException致应用重启

虚拟线程join时被中断导致应用崩溃的排查与解决

问题背景

应用基于Zulu OpenJDK 21 + Spring Boot构建,为高效管理线程封装了等待多线程完成的工具方法joinThreads,运行约5天后出现InterruptedException,导致应用崩溃重启;重启后可正常运行一段时间。

核心代码

public static void joinThreads(Thread... threadList) {
    try {
        for (Thread thread : threadList) {
            if (thread == null) {
                continue;
            }
            thread.join();
        }
    } catch (InterruptedException e) {
        log.error("Virtual thread task exception", e);
        throw new BizException(CodeEnum.INTERNAL_BUSINESS_FAIL, "Virtual thread task was interrupted");
    }
}

异常栈信息

ERROR com.xmonecode.tccompass.common.utils.VirtualThreadUtil - Virtual thread task exception java.lang.InterruptedException: null
    at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1100)
    at java.base/java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230)
    at java.base/java.lang.VirtualThread.joinNanos(VirtualThread.java:824)
    at java.base/java.lang.Thread.join(Thread.java:2061)
    at java.base/java.lang.Thread.join(Thread.java:2154)
    at com.xmonecode.tccompass.common.utils.VirtualThreadUtil.joinThreads(VirtualThreadUtil.java:40)
    at com.xmonecode.tccompass.common.utils.VirtualThreadUtil.joinStartVirtualThread(VirtualThreadUtil.java:70)
    at com.xmonecode.tccompass.interceptor.RebateInterceptor.preHandle(RebateInterceptor.java:45)
    at org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle(HandlerExecutionChain.java:146)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1084)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)

额外环境信息

  • JDK版本:zulu-openjdk:21
  • 框架:Spring Boot
  • 异常触发位置:CountDownLatch.await() 和 VirtualThread.joinNanos() 调用过程中
  • 运行环境:容器化部署,崩溃后自动重启

排查与解决建议

  • 检查容器层面的中断信号:容器环境下,资源超限(如OOM触发内核杀死进程)、健康探测失败(K8s liveness/readiness探针)、运维操作等都可能向进程发送中断信号。查看容器日志、宿主机dmesg日志(OOM记录)、K8s事件等,确认是否有外部触发的中断。
  • 排查HTTP请求超时:异常发生在Spring MVC拦截器的preHandle阶段,若请求超时(如Tomcat的connectionTimeout、Spring Boot的server.servlet.session.timeout或接口级别的超时配置),容器会中断请求处理线程,进而导致关联的虚拟线程join操作被中断。检查相关超时配置是否合理。
  • 定位代码内部的中断源:排查应用中是否有其他代码调用Thread.interrupt()方法,尤其是针对虚拟线程或其所在线程组。可在joinThreads方法中增加日志,记录当前线程、待join线程的信息,以及中断发生时的线程栈,帮助定位。
  • 检查JDK版本问题:确认Zulu OpenJDK 21是否存在虚拟线程join相关的已知bug,尝试升级到最新的Zulu 21小版本,修复可能的底层问题。
  • 优化异常处理逻辑:当前捕获中断后直接抛出异常导致应用崩溃,可改为恢复中断状态、记录详细日志后优雅降级,避免应用直接崩溃。示例修改:
public static void joinThreads(Thread... threadList) {
    try {
        for (Thread thread : threadList) {
            if (thread == null) {
                continue;
            }
            thread.join();
        }
    } catch (InterruptedException e) {
        // 恢复中断状态,让上层处理
        Thread.currentThread().interrupt();
        log.error("线程join被中断,当前线程: {}, 待join线程: {}", 
                  Thread.currentThread().getName(), 
                  Arrays.stream(threadList).filter(Objects::nonNull).map(Thread::getName).toList(), 
                  e);
        // 根据业务场景选择降级逻辑,而非直接抛出致命异常
        // throw new BizException(CodeEnum.INTERNAL_BUSINESS_FAIL, "Virtual thread task was interrupted");
    }
}
  • 增加线程监控:通过Micrometer等工具监控虚拟线程的数量、状态,记录中断发生时的上下文信息,便于后续分析触发场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 12:37:17