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

使用newVirtualThreadPerTaskExecutor时程序提前退出问题排查

问题分析与解决方案

问题原因

程序直接退出的核心原因是:主线程提交完任务后立即执行完毕,JVM终止了所有虚拟线程。

Executors.newVirtualThreadPerTaskExecutor() 创建的虚拟线程池,其内部的虚拟线程默认以守护线程模式运行。当主线程(main方法)执行完所有代码后,JVM会检查是否还有非守护线程在运行——此时仅剩的虚拟线程都是守护线程,JVM会直接终止所有守护线程,导致程序提前退出,用户还没来得及输入内容。

另外,第二个线程的逻辑存在效率问题:通过isEmpty()判断后调用poll()的方式属于空轮询,会持续占用CPU资源,且isEmpty()和poll()的组合并非原子操作,存在线程安全隐患。

修复方案

方案1:让主线程持续阻塞,避免JVM退出

在main方法末尾添加阻塞逻辑,让主线程一直处于等待状态,保证虚拟线程能持续运行:

public static void main(String[] args) {
    // 提交两个任务的代码不变...

    // 让主线程无限阻塞,防止JVM退出
    try {
        Thread.currentThread().join();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}

方案2:优化消费线程的逻辑(推荐)

将消费线程中的isEmpty()+poll()替换为LinkedBlockingQueue的take()方法,该方法会阻塞直到队列中有元素,既避免空轮询浪费CPU,又保证线程安全:

executor.submit(() -> {
    try {
        while (true) {
            // take()会阻塞等待,直到队列中有元素
            String name = names.take();
            System.out.println("\n**** The name is " + name + " ****\n");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
});

完整修复后的代码

import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

public class TestThreads {
    private static final Scanner scanner = new Scanner(System.in);
    private static ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
    private static LinkedBlockingQueue<String> names = new LinkedBlockingQueue<>();
    
    public static void main(String[] args) {
        executor.submit(() -> {
            try {
                while (true) {
                    String name = getName();
                    names.add(name);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        executor.submit(() -> {
            try {
                while (true) {
                    String name = names.take();
                    System.out.println("\n**** The name is " + name + " ****\n");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        // 阻塞主线程,防止JVM提前退出
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    private static String getName() {
        System.out.print("Enter a name: ");
        return scanner.nextLine();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:40:03