Java 17 虚拟线程与线程池混合使用方案

林欢喜 Java经验 发布时间:2026-01-07 17:45:40 阅读数:6818 1
下文笔者讲述java17中虚拟线程(Virtual Threads)与传统的线程池结合使用的简介说明,如下所示

虚拟线程与线程池的简介说明

虚拟线程(JVM 层面的轻量级线程)适合处理IO 密集型、
    阻塞等待的任务,
    而线程池(平台线程池)适合管理资源、控制并发度。
混合使用的核心思路是:
   1. 用线程池管理平台线程(载体),
          由平台线程来启动虚拟线程;
   2. 虚拟线程执行具体的阻塞/IO 任务,
          避免平台线程被阻塞,提升整体吞吐量;
   3. 区分任务类型:
          CPU密集型任务仍用传统线程池
          IO密集型任务通过线程池调度虚拟线程执行。

方案1:线程池+虚拟线程工厂

使用`Executors.defaultThreadFactory()` 或自定义工厂,
    让线程池的平台线程作为“调度器”,
    启动虚拟线程执行任务

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class VirtualThreadWithThreadPool {

    public static void main(String[] args) throws InterruptedException {
        // 1. 创建传统平台线程池(核心作用:控制并发调度的平台线程数)
        // 适合IO密集型场景:核心线程数可设为CPU核心数,避免平台线程过多竞争
        ExecutorService platformThreadPool = Executors.newFixedThreadPool(
                Runtime.getRuntime().availableProcessors() // CPU核心数,如8核设为8
        );

        // 2. 提交1000个IO密集型任务,由线程池的平台线程启动虚拟线程执行
        for (int i = 0; i < 1000; i++) {
            int taskId = i;
            platformThreadPool.submit(() -> {
                // 3. 启动虚拟线程执行具体的阻塞任务
                Thread.startVirtualThread(() -> {
                    try {
                        // 模拟IO阻塞(如数据库查询、网络请求)
                        TimeUnit.MILLISECONDS.sleep(100);
                        System.out.printf("虚拟线程执行任务%d,载体平台线程:%s%n",
                                taskId, Thread.currentThread().getCarrierThread().getName());
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException(e);
                    }
                });
            });
        }

        // 4. 优雅关闭线程池
        platformThreadPool.shutdown();
        if (!platformThreadPool.awaitTermination(10, TimeUnit.SECONDS)) {
            platformThreadPool.shutdownNow();
        }
    }
}

方案2:自定义虚拟线程池(JDK 19+预览,17需手动封装)

Java 17 中虚拟线程没有官方的“虚拟线程池"
    但可封装 `Executors.newVirtualThreadPerTaskExecutor()`
      结合线程池的拒绝策略、生命周期管理:


import java.util.concurrent.;

public class CustomVirtualThreadPool {

    // 核心:用平台线程池做调度,虚拟线程执行任务
    private final ExecutorService platformExecutor;
    // 虚拟线程执行器(每个任务一个虚拟线程)
    private final ExecutorService virtualExecutor;

    public CustomVirtualThreadPool(int corePlatformThreads) {
        // 1. 平台线程池:控制调度并发度
        this.platformExecutor = new ThreadPoolExecutor(
                corePlatformThreads,
                corePlatformThreads,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(),
                // 平台线程工厂(命名便于排查)
                new ThreadFactory() {
                    private int count = 0;
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(r);
                        t.setName("platform-scheduler-" + count++);
                        return t;
                    }
                }
        );

        // 2. 虚拟线程执行器(Java 17+支持)
        this.virtualExecutor = Executors.newVirtualThreadPerTaskExecutor();
    }

    // 提交任务:由平台线程调度,虚拟线程执行
    public <T> Future<T> submit(Callable<T> task) {
        return platformExecutor.submit(() -> {
            // 用虚拟线程执行具体任务
            return virtualExecutor.submit(task).get();
        });
    }

    // 优雅关闭
    public void shutdown() throws InterruptedException {
        virtualExecutor.shutdown();
        platformExecutor.shutdown();
        if (!platformExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
            platformExecutor.shutdownNow();
            virtualExecutor.shutdownNow();
        }
    }

    // 测试
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        CustomVirtualThreadPool pool = new CustomVirtualThreadPool(Runtime.getRuntime().availableProcessors());

        // 提交100个IO任务
        for (int i = 0; i < 100; i++) {
            int taskId = i;
            Future<String> future = pool.submit(() -> {
                TimeUnit.MILLISECONDS.sleep(50); // 模拟IO阻塞
                return "任务" + taskId + "完成,虚拟线程:" + Thread.currentThread().getName();
            });
            System.out.println(future.get());
        }

        pool.shutdown();
    }
}

注意事项

1. 任务类型区分:
   - CPU 密集型任务(如计算、循环):
       直接用传统线程池(平台线程),虚拟线程无优势;
   - IO 密集型任务(如网络请求、数据库操作):
      用“线程池+虚拟线程”,最大化吞吐量。
2. 资源控制:
   - 平台线程池的核心线程数建议设为 `CPU核心数`(如 8 核设 8)
       避免平台线程过多导致上下文切换;
   - 虚拟线程数量无上限(JVM 自动管理),无需限制。
3. 异常处理:
   虚拟线程的异常不会自动打印,需在任务内捕获,
       或通过 `Future.get()` 获取异常。
4. 兼容性:
   Java 17 中虚拟线程是预览特性(需启动参数 `--enable-preview`),
      Java 21 中正式转正,生产环境建议升级到 Java 21 或确保启动参数正确。

 总结
1. 核心方案:用传统平台线程池控制并发调度度,
     由平台线程启动虚拟线程执行 IO 密集型阻塞任务,
      兼顾资源管理和轻量级优势;
2. 关键原则:CPU 密集型用平台线程池,
      IO 密集型用“平台线程池+虚拟线程”;
3. 实践要点:平台线程池核心数设为 CPU 核心数,
     做好虚拟线程的异常捕获和线程池优雅关闭。
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaJingYan/202601/17677791828535.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者