Java 虚拟线程技术详解:原理、实践与优化(下)

67 阅读18分钟

在上一部分中,我们介绍了 Java 虚拟线程的基础概念、创建方法、性能优化技巧、常见问题解决方案以及与主流框架的整合。接下来,我们将深入探讨虚拟线程的高级应用场景,包括迁移策略、大规模部署、内部实现和性能对比等内容,帮助您在实际项目中充分利用虚拟线程的优势。

6. 从传统线程池迁移策略

6.1 迁移路径图

迁移路径图.png

6.2 迁移检查项目

检查项描述迁移复杂度
线程池配置找出所有 Executors 和 ThreadPoolExecutor 创建点
线程本地变量检查 ThreadLocal 使用,确保清理机制
同步块标识 synchronized 块并评估替换方案
原生方法识别 JNI 调用和阻塞原生库
线程管理代码查找直接操作 Thread 对象的代码
JDBC 操作检查数据库访问模式和驱动兼容性
第三方库评估库的线程使用模式
监控系统确认现有监控工具对虚拟线程的支持

6.3 代码转换示例

// 简单的线程池替换
// 旧代码
ExecutorService executor = Executors.newFixedThreadPool(100);

// 新代码 - 虚拟线程
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

// 混合模式 - 根据任务类型选择池
class HybridExecutorService implements AutoCloseable {
    private final ExecutorService cpuBoundTasks =
        Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    private final ExecutorService ioBoundTasks =
        Executors.newVirtualThreadPerTaskExecutor();

    public void executeCpuTask(Runnable task) {
        cpuBoundTasks.execute(task);
    }

    public void executeIoTask(Runnable task) {
        ioBoundTasks.execute(task);
    }

    @Override
    public void close() {
        cpuBoundTasks.shutdown();
        ioBoundTasks.shutdown();
    }
}

// 带配置的动态切换模式
class ConfigurableExecutorService implements AutoCloseable {
    private final boolean useVirtualThreads;
    private final ExecutorService executor;

    public ConfigurableExecutorService(boolean useVirtualThreads, int poolSize) {
        this.useVirtualThreads = useVirtualThreads;

        if (useVirtualThreads) {
            this.executor = Executors.newVirtualThreadPerTaskExecutor();
        } else {
            this.executor = Executors.newFixedThreadPool(poolSize);
        }
    }

    public ExecutorService getExecutor() {
        return executor;
    }

    @Override
    public void close() {
        executor.shutdown();
    }
}

6.4 渐进式迁移案例

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 演示如何从传统线程池渐进式迁移到虚拟线程
 */
public class ProgressiveMigrationExample {
    private static final Logger logger = LoggerFactory.getLogger(ProgressiveMigrationExample.class);

    public static void main(String[] args) {
        // 创建迁移管理器 - 初始使用传统线程池
        ExecutorMigrationManager manager = new ExecutorMigrationManager(false);

        // 使用当前配置的执行器处理一些任务
        try (ExecutorService executor = manager.getCurrentExecutor()) {
            for (int i = 0; i < 1000; i++) {
                final int taskId = i;
                executor.submit(() -> processTask(taskId));
            }
        }

        // 在运行时切换到虚拟线程
        manager.switchToVirtualThreads();
        logger.info("已切换到虚拟线程");

        // 使用虚拟线程执行更多任务
        try (ExecutorService executor = manager.getCurrentExecutor()) {
            for (int i = 0; i < 1000; i++) {
                final int taskId = i + 1000;
                executor.submit(() -> processTask(taskId));
            }
        }

        // 检查性能数据
        logger.info("执行性能统计: {}", manager.getPerformanceStats());
    }

    private static void processTask(int taskId) {
        try {
            // 模拟I/O操作
            Thread.sleep(10);
            logger.debug("任务{}完成于线程: {}", taskId, Thread.currentThread());
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 执行器迁移管理器 - 支持运行时切换线程池实现
     */
    static class ExecutorMigrationManager {
        private final AtomicReference<Function<Integer, ExecutorService>> executorFactory;
        private final PerformanceMonitor performanceMonitor = new PerformanceMonitor();
        private volatile boolean useVirtualThreads;

        public ExecutorMigrationManager(boolean initialUseVirtualThreads) {
            this.useVirtualThreads = initialUseVirtualThreads;
            this.executorFactory = new AtomicReference<>(this::createExecutor);
        }

        /**
         * 获取当前配置的执行器
         */
        public ExecutorService getCurrentExecutor() {
            return new MonitoredExecutorService(
                executorFactory.get().apply(Runtime.getRuntime().availableProcessors()),
                performanceMonitor
            );
        }

        /**
         * 切换到虚拟线程执行模式
         */
        public void switchToVirtualThreads() {
            useVirtualThreads = true;
        }

        /**
         * 切换到传统线程池执行模式
         */
        public void switchToTraditionalThreadPool() {
            useVirtualThreads = false;
        }

        /**
         * 获取性能统计数据
         */
        public PerformanceStats getPerformanceStats() {
            return performanceMonitor.getStats();
        }

        private ExecutorService createExecutor(int poolSize) {
            if (useVirtualThreads) {
                return Executors.newVirtualThreadPerTaskExecutor();
            } else {
                return Executors.newFixedThreadPool(poolSize);
            }
        }
    }

    /**
     * 执行器性能监控包装类
     */
    static class MonitoredExecutorService implements ExecutorService {
        private final ExecutorService delegate;
        private final PerformanceMonitor monitor;

        public MonitoredExecutorService(ExecutorService delegate, PerformanceMonitor monitor) {
            this.delegate = delegate;
            this.monitor = monitor;
        }

        @Override
        public void execute(Runnable command) {
            long startTime = System.nanoTime();
            delegate.execute(() -> {
                try {
                    command.run();
                } finally {
                    monitor.recordTaskCompletion(System.nanoTime() - startTime);
                }
            });
            monitor.recordTaskSubmission();
        }

        // 其他ExecutorService方法实现省略...
        // 这些方法都应该委托给delegate并添加监控逻辑

        @Override
        public void shutdown() {
            delegate.shutdown();
        }

        @Override
        public List<Runnable> shutdownNow() {
            return delegate.shutdownNow();
        }

        @Override
        public boolean isShutdown() {
            return delegate.isShutdown();
        }

        @Override
        public boolean isTerminated() {
            return delegate.isTerminated();
        }

        @Override
        public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
            return delegate.awaitTermination(timeout, unit);
        }

        // 实现其他ExecutorService方法...
    }

    /**
     * 性能监控器
     */
    static class PerformanceMonitor {
        private final AtomicLong tasksSubmitted = new AtomicLong();
        private final AtomicLong tasksCompleted = new AtomicLong();
        private final AtomicLong totalTaskTimeNanos = new AtomicLong();

        public void recordTaskSubmission() {
            tasksSubmitted.incrementAndGet();
        }

        public void recordTaskCompletion(long durationNanos) {
            tasksCompleted.incrementAndGet();
            totalTaskTimeNanos.addAndGet(durationNanos);
        }

        public PerformanceStats getStats() {
            long completed = tasksCompleted.get();
            long totalTimeNanos = totalTaskTimeNanos.get();
            double avgTimeMillis = completed > 0
                ? (double) totalTimeNanos / completed / 1_000_000
                : 0;

            return new PerformanceStats(
                tasksSubmitted.get(),
                completed,
                avgTimeMillis
            );
        }
    }

    /**
     * 性能统计数据
     */
    record PerformanceStats(long tasksSubmitted, long tasksCompleted, double avgTaskTimeMillis) {}
}

7. 实际案例:高并发 Web 服务器

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class VirtualThreadWebServer {
    private static final Logger logger = LoggerFactory.getLogger(VirtualThreadWebServer.class);

    // 性能指标收集
    private static final AtomicInteger activeRequests = new AtomicInteger();
    private static final AtomicLong totalRequests = new AtomicLong();
    private static final AtomicLong totalProcessingTime = new AtomicLong();

    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);

        // 为服务器设置虚拟线程执行器
        server.setExecutor(Executors.newVirtualThreadPerTaskExecutor());

        // 注册多个处理程序
        server.createContext("/api/data", new DataHandler());
        server.createContext("/api/users", new UserHandler());
        server.createContext("/api/health", new HealthCheckHandler());
        server.createContext("/metrics", new MetricsHandler());

        // 启动监控
        VirtualThreadMonitoring.startMonitoring();

        // 添加关闭钩子实现优雅终止
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            logger.info("接收到终止信号,开始优雅关闭...");
            server.stop(5); // 给5秒完成正在处理的请求
            logger.info("服务器已关闭");
        }));

        server.start();
        logger.info("服务器已启动,端口: 8080");
    }

    // 使用Semaphore实现流量控制,CircuitBreaker实现熔断保护
    static class DataHandler implements HttpHandler {
        private final Semaphore concurrencyLimiter = new Semaphore(1000);
        private final CircuitBreaker circuitBreaker = new CircuitBreaker("data-api", 5, 30000);

        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String requestId = UUID.randomUUID().toString();
            MDC.put("requestId", requestId);
            exchange.getResponseHeaders().set("X-Request-ID", requestId);

            String requestMethod = exchange.getRequestMethod();
            String path = exchange.getRequestURI().getPath();
            String query = exchange.getRequestURI().getQuery();

            logger.info("收到{}请求: {}, 查询参数: {}", requestMethod, path, query);

            long startTime = System.currentTimeMillis();
            int activeCount = activeRequests.incrementAndGet();
            logger.debug("当前活动请求数: {}", activeCount);

            try {
                // 请求限流
                if (!concurrencyLimiter.tryAcquire()) {
                    logger.warn("请求过多,触发限流");
                    exchange.sendResponseHeaders(429, 0);
                    return;
                }

                try {
                    // 使用熔断器执行业务逻辑
                    CircuitState currentState = circuitBreaker.getState();
                    if (currentState == CircuitState.OPEN) {
                        logger.warn("熔断器[{}]断开中,拒绝请求", "data-api");
                        exchange.sendResponseHeaders(503, 0); // 服务不可用
                        return;
                    }

                    try {
                        String response = circuitBreaker.execute(() -> {
                            try {
                                // 模拟I/O操作,如数据库查询
                                Thread.sleep(200);
                                return """
                                    {"status":"success","data":{"id":123,"name":"Sample"}}
                                    """;
                            } catch (InterruptedException e) {
                                Thread.currentThread().interrupt();
                                throw new RuntimeException("处理被中断", e);
                            }
                        });

                        exchange.getResponseHeaders().set("Content-Type", "application/json");
                        exchange.sendResponseHeaders(200, response.length());

                        try (OutputStream os = exchange.getResponseBody()) {
                            os.write(response.getBytes());
                        }
                    } catch (CircuitBreakerOpenException e) {
                        logger.warn("熔断器已打开,请求被拒绝", e);
                        exchange.sendResponseHeaders(503, 0); // 服务不可用
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    logger.error("处理请求时中断 [path={}, method={}]", path, requestMethod, e);
                    exchange.sendResponseHeaders(500, 0);
                } catch (IOException e) {
                    logger.error("I/O错误 [path={}, method={}]", path, requestMethod, e);
                    exchange.sendResponseHeaders(500, 0);
                } catch (Exception e) {
                    logger.error("处理请求时出错 [path={}, method={}]", path, requestMethod, e);
                    exchange.sendResponseHeaders(500, 0);
                } finally {
                    concurrencyLimiter.release();
                }
            } finally {
                long duration = System.currentTimeMillis() - startTime;
                totalProcessingTime.addAndGet(duration);
                totalRequests.incrementAndGet();
                activeRequests.decrementAndGet();

                logger.info("请求处理完成,耗时: {}ms", duration);
                exchange.close();
                MDC.remove("requestId");
            }
        }
    }

    // 指标监控处理器
    static class MetricsHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            if (!"GET".equals(exchange.getRequestMethod())) {
                exchange.sendResponseHeaders(405, 0); // Method Not Allowed
                exchange.close();
                return;
            }

            long totalReqs = totalRequests.get();
            long avgTime = totalReqs > 0
                ? totalProcessingTime.get() / totalReqs
                : 0;

            String metrics = String.format("""
                # 虚拟线程Web服务器指标
                active_requests %d
                total_requests %d
                avg_processing_time_ms %d
                """,
                activeRequests.get(),
                totalReqs,
                avgTime);

            exchange.getResponseHeaders().set("Content-Type", "text/plain");
            exchange.sendResponseHeaders(200, metrics.length());

            try (OutputStream os = exchange.getResponseBody()) {
                os.write(metrics.getBytes());
            }
        }
    }

    // 其他处理程序类实现略...
    static class UserHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            // 用户处理逻辑
        }
    }

    static class HealthCheckHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            // 健康检查逻辑
            String status = """
                {"status":"UP","components":{
                "virtualThreads":{"status":"UP","count":%d},
                "circuitBreaker":{"status":"UP","state":"%s"}
                }}
                """.formatted(Thread.activeCount(), CircuitState.CLOSED);

            exchange.getResponseHeaders().set("Content-Type", "application/json");
            exchange.sendResponseHeaders(200, status.length());

            try (OutputStream os = exchange.getResponseBody()) {
                os.write(status.getBytes());
            }
        }
    }

    // 熔断器状态枚举
    enum CircuitState {
        CLOSED,    // 正常状态,允许请求通过
        OPEN,      // 熔断状态,拒绝所有请求
        HALF_OPEN  // 半开状态,允许少量请求尝试恢复
    }

    // CircuitBreakerOpenException 和 CircuitBreaker 实现省略
}

8. 虚拟线程内部结构分析

以下是虚拟线程的简化内部结构及关键组件分析:

虚拟线程内部结构分析.png

8.1 关键源码分析

虚拟线程的核心实现位于jdk.internal.vm.Continuationjava.lang.VirtualThread类中:

// 虚拟线程的简化内部实现
class VirtualThread extends Thread {
    // 线程状态
    private enum State { NEW, STARTED, TERMINATED, ... }

    // 当前状态
    private volatile State state;

    // 底层延续对象
    private final Continuation continuation;

    // 当前承载线程
    private volatile CarrierThread carrier;

    // 挂载状态
    private volatile boolean mounted;

    // 运行虚拟线程的主要方法
    void run() {
        // 调度器分配承载线程
        scheduler.mount(this);

        // 在承载线程上执行
        continuation.run();

        // 执行完成或挂起后
        if (continuation.isDone()) {
            state = State.TERMINATED;
        } else {
            // 将在之后恢复
            scheduler.unmount(this);
        }
    }

    // 挂起点检测
    boolean isYieldPoint(Method method) {
        return method.isBlocking() && !method.isNative();
    }
}

// 延续的简化内部实现
class Continuation {
    // 延续范围
    private final ContinuationScope scope;

    // 任务代码
    private final Runnable target;

    // 栈快照
    private StackChunk stackChunk;

    // 执行状态
    private boolean done;

    void run() {
        // 检查是否已完成
        if (done) return;

        // 新运行或恢复之前的执行
        if (stackChunk == null) {
            // 首次运行
            try {
                target.run();
                done = true;
            } catch (YieldException e) {
                // 捕获挂起点
                stackChunk = captureStack();
            }
        } else {
            // 恢复之前的执行
            try {
                restoreStack(stackChunk);
                done = true;
            } catch (YieldException e) {
                // 再次挂起
                stackChunk = captureStack();
            }
        }
    }
}

8.2 内存使用分析

虚拟线程相比平台线程的内存优势:

组件平台线程虚拟线程说明
栈空间1MB (固定)~5-10KB (动态)虚拟线程栈按需分配
内核资源系统线程共享少量系统线程大幅减少系统资源使用
上下文切换硬件级切换软件级切换减少系统调用开销
创建成本~1ms~0.1ms创建速度提升约 10 倍
内存总开销~2MB/线程~2KB/线程总体内存减少约 1000 倍

8.3 不同 GC 算法对虚拟线程性能影响

GC 算法虚拟线程性能影响建议场景
ZGC最佳,停顿时间短高并发生产环境
G1良好,平衡吞吐量和停顿中等并发负载
Parallel GC高吞吐量但停顿长批处理任务
Serial GC不推荐,长停顿影响响应仅用于小型应用

8.4 虚拟线程与 CPU 亲和性

在高并发场景下,CPU 亲和性(CPU affinity)设置可能影响虚拟线程性能:

import java.lang.management.ManagementFactory;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class VirtualThreadCpuAffinityExample {
    private static final Logger logger = LoggerFactory.getLogger(VirtualThreadCpuAffinityExample.class);

    public static void main(String[] args) {
        // 获取可用处理器数量
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        logger.info("系统可用处理器数量: {}", availableProcessors);

        // 获取JVM进程ID
        String jvmName = ManagementFactory.getRuntimeMXBean().getName();
        String pid = jvmName.split("@")[0];
        logger.info("JVM进程ID: {}", pid);

        logger.info("注意: 在Linux上可以使用taskset命令设置CPU亲和性");
        logger.info("例如: taskset -c 0-3 java -jar myapp.jar");

        // 使用虚拟线程时CPU亲和性注意事项
        logger.info("虚拟线程最佳实践:");
        logger.info("1. 允许JVM使用所有可用核心以最大化承载线程池效率");
        logger.info("2. 避免将JVM固定到单个CPU核心,这会严重影响虚拟线程性能");
        logger.info("3. 对于NUMA架构,考虑使用-XX:+UseNUMA JVM参数");

        // 测试虚拟线程CPU使用
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 100_000; i++) {
                executor.submit(() -> {
                    // 简单计算任务
                    double result = 0;
                    for (int j = 0; j < 10_000; j++) {
                        result += Math.sqrt(j);
                    }
                    return result;
                });
            }

            logger.info("已提交100,000个计算任务到虚拟线程");
        }
    }
}

9. 性能测试对比

在 8 核 16GB RAM 服务器上进行的基准测试结果:

性能测试对比.png

9.1 高负载测试

使用 JMeter 对 REST API 进行的 10 分钟压力测试结果:

线程模型并发吞吐量(req/sec)平均响应时间错误率内存使用
平台线程(200 线程池)1,000856234ms0.02%1.8GB
平台线程(200 线程池)5,0009125,481ms4.35%2.3GB
虚拟线程1,000978102ms0.01%350MB
虚拟线程5,0003,245154ms0.03%720MB
虚拟线程20,0005,123390ms0.12%1.2GB
虚拟线程100,0005,8451,250ms0.45%2.7GB

9.2 真实业务场景性能

微服务架构中 API 聚合服务的实际业务指标:

指标传统线程池虚拟线程提升比例
峰值处理能力1,800 req/sec7,200 req/sec4 倍
平均响应时间350ms95ms73%
95%分位响应时间750ms220ms71%
错误率0.8%0.2%75%
最大并发连接2,00025,00012.5 倍
服务器数量8362.5%

9.3 不同 CPU 架构下的性能比较

在同等配置的 x86 和 ARM 服务器上进行的对比测试:

架构平台并发吞吐量(req/sec)平均响应时间内存使用
x86-64Intel Xeon10,0004,520220ms1.2GB
ARM64AWS Graviton310,0005,150194ms1.0GB
x86-64AMD EPYC10,0004,780209ms1.1GB

9.4 性能测试工具实现

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 虚拟线程性能测试工具
 */
public class VirtualThreadBenchmark {
    private static final Logger logger = LoggerFactory.getLogger(VirtualThreadBenchmark.class);

    // 测试参数
    private final String targetUrl;
    private final int concurrentUsers;
    private final int requestsPerUser;
    private final int warmupRequests;

    // 性能统计
    private final AtomicInteger completedRequests = new AtomicInteger();
    private final AtomicInteger failedRequests = new AtomicInteger();
    private final AtomicLong totalResponseTime = new AtomicLong();
    private final List<Long> responseTimes = new ArrayList<>();

    // 监控资源使用
    private final Runtime runtime = Runtime.getRuntime();

    public VirtualThreadBenchmark(String targetUrl, int concurrentUsers,
                                 int requestsPerUser, int warmupRequests) {
        this.targetUrl = targetUrl;
        this.concurrentUsers = concurrentUsers;
        this.requestsPerUser = requestsPerUser;
        this.warmupRequests = warmupRequests;
    }

    public void run() throws Exception {
        logger.info("开始性能测试: 目标URL={}, 并发用户={}, 每用户请求数={}",
                   targetUrl, concurrentUsers, requestsPerUser);

        // 创建HTTP客户端
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))
                .build();

        // 预热阶段
        logger.info("开始预热 ({} 请求)...", warmupRequests);
        for (int i = 0; i < warmupRequests; i++) {
            sendRequest(client, targetUrl);
        }

        // 重置统计数据
        completedRequests.set(0);
        failedRequests.set(0);
        totalResponseTime.set(0);
        responseTimes.clear();

        // 主测试阶段
        logger.info("开始主测试...");
        long startMemory = usedMemory();
        long startTime = System.currentTimeMillis();

        // 使用虚拟线程执行测试
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            List<Future<?>> futures = new ArrayList<>();

            // 模拟并发用户
            for (int user = 0; user < concurrentUsers; user++) {
                futures.add(executor.submit(() -> {
                    for (int req = 0; req < requestsPerUser; req++) {
                        try {
                            long responseTime = sendRequest(client, targetUrl);
                            synchronized (responseTimes) {
                                responseTimes.add(responseTime);
                            }
                            completedRequests.incrementAndGet();
                            totalResponseTime.addAndGet(responseTime);
                        } catch (Exception e) {
                            failedRequests.incrementAndGet();
                            logger.debug("请求失败: {}", e.getMessage());
                        }
                    }
                }));
            }

            // 等待所有任务完成
            for (Future<?> future : futures) {
                future.get();
            }
        }

        long endTime = System.currentTimeMillis();
        long endMemory = usedMemory();
        long totalTime = endTime - startTime;

        // 计算性能指标
        int totalRequests = completedRequests.get() + failedRequests.get();
        double requestsPerSecond = (double) completedRequests.get() / (totalTime / 1000.0);
        double avgResponseTime = completedRequests.get() > 0
            ? (double) totalResponseTime.get() / completedRequests.get()
            : 0;
        double errorRate = totalRequests > 0
            ? (double) failedRequests.get() / totalRequests * 100
            : 0;

        // 计算百分位数据
        List<Long> sortedTimes;
        synchronized (responseTimes) {
            sortedTimes = new ArrayList<>(responseTimes);
        }
        sortedTimes.sort(Long::compare);

        long p50 = percentile(sortedTimes, 50);
        long p90 = percentile(sortedTimes, 90);
        long p95 = percentile(sortedTimes, 95);
        long p99 = percentile(sortedTimes, 99);

        // 输出结果
        logger.info("测试完成! 结果摘要:");
        logger.info("总请求数: {}", totalRequests);
        logger.info("完成请求: {}", completedRequests.get());
        logger.info("失败请求: {}", failedRequests.get());
        logger.info("错误率: {}%", String.format("%.2f", errorRate));
        logger.info("总执行时间: {}ms", totalTime);
        logger.info("吞吐量: {} 请求/秒", String.format("%.2f", requestsPerSecond));
        logger.info("平均响应时间: {}ms", String.format("%.2f", avgResponseTime));
        logger.info("响应时间百分位: P50={}ms, P90={}ms, P95={}ms, P99={}ms",
                   p50, p90, p95, p99);
        logger.info("内存使用: {}MB -> {}MB (增加: {}MB)",
                   startMemory / (1024 * 1024),
                   endMemory / (1024 * 1024),
                   (endMemory - startMemory) / (1024 * 1024));
    }

    private long sendRequest(HttpClient client, String url) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();

        long startTime = System.nanoTime();
        HttpResponse<String> response = client.send(request,
                                                  HttpResponse.BodyHandlers.ofString());
        long endTime = System.nanoTime();

        if (response.statusCode() >= 400) {
            throw new RuntimeException("HTTP错误: " + response.statusCode());
        }

        return (endTime - startTime) / 1_000_000; // 转换为毫秒
    }

    private long usedMemory() {
        runtime.gc(); // 提示进行垃圾回收以获得更准确的内存使用数据
        return runtime.totalMemory() - runtime.freeMemory();
    }

    private long percentile(List<Long> sortedValues, int percentile) {
        if (sortedValues.isEmpty()) return 0;
        int index = (int) Math.ceil((percentile / 100.0) * sortedValues.size()) - 1;
        return sortedValues.get(Math.max(0, Math.min(sortedValues.size() - 1, index)));
    }

    public static void main(String[] args) throws Exception {
        // 示例使用
        VirtualThreadBenchmark benchmark = new VirtualThreadBenchmark(
            "http://localhost:8080/api/data",
            1000, // 并发用户
            100,  // 每用户请求数
            1000  // 预热请求数
        );

        benchmark.run();
    }
}

10. 大规模部署建议

10.1 JVM 参数优化

# 推荐的JVM参数
-XX:+UseZGC
-XX:+ZGenerational
-XX:+AutoCreateSharedArchive
-XX:+UseStringDeduplication
-XX:MaxDirectMemorySize=512m
-XX:+ExitOnOutOfMemoryError
-XX:+HeapDumpOnOutOfMemoryError

10.2 系统配置

  • 文件描述符限制增加: ulimit -n 1000000
  • 内核参数优化:
    • net.core.somaxconn=65535
    • net.ipv4.tcp_max_syn_backlog=65535
    • net.ipv4.ip_local_port_range="1024 65535"
    • vm.max_map_count=262144

10.3 最佳方法总结

  • 使用 NIO 和异步 API
  • 避免线程固定操作
  • 定期监控 JFR 事件
  • 适当配置垃圾收集器
  • 控制并发虚拟线程数量(某些场景需要限制)
  • 设置合理的超时策略
  • 实现适当的背压机制
  • 定期检查内存使用

10.4 容器环境优化

在 Docker 和 Kubernetes 环境中运行虚拟线程应用需要特别注意:

  • CPU 限制

    • 虚拟线程调度器依赖于承载线程池,默认为系统 CPU 核心数
    • 容器 CPU 限制应合理设置,避免承载线程被过度限制
    • 推荐设置:-XX:ActiveProcessorCount=<n> 明确告知 JVM 可用处理器数量
  • 内存限制

    • 大量虚拟线程会占用堆外内存,设置合理的容器内存限制
    • 虚拟线程栈虽小,但数量巨大时仍需注意总内存占用
    • 设置:-XX:MaxRAMPercentage=75.0 而非固定堆大小
  • Kubernetes 配置建议

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: vthread-application
    spec:
      replicas: 3
      template:
        spec:
          containers:
          - name: vthread-app
            image: vthread-app:latest
            resources:
              requests:
                memory: "1Gi"
                cpu: "2"
              limits:
                memory: "2Gi"
                cpu: "4"
            env:
            - name: JAVA_OPTS
              value: "-XX:+UseZGC -XX:+ZGenerational -XX:ActiveProcessorCount=4 -XX:MaxRAMPercentage=75.0"
            readinessProbe:
              httpGet:
                path: /api/health
                port: 8080
              initialDelaySeconds: 10
              periodSeconds: 5
            livenessProbe:
              httpGet:
                path: /api/health
                port: 8080
              initialDelaySeconds: 20
              periodSeconds: 15
            lifecycle:
              preStop:
                exec:
                  command: ["sh", "-c", "sleep 10"]  # 优雅关闭时间
          terminationGracePeriodSeconds: 30
    
  • 优雅关闭处理

    • 实现正确的 SIGTERM 信号处理
    • 在停止前完成所有正在执行的虚拟线程
    • 设置合理的 terminationGracePeriodSeconds (至少 30 秒)
  • 容器健康检查

    • 添加线程状态监控的健康检查端点
    • 监控虚拟线程固定情况作为健康状态指标

10.5 监控与可观测性

在生产环境中,应建立全面的监控系统:

import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.Gauge;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 虚拟线程应用监控
 */
public class VirtualThreadMonitoringSystem {
    private static final Logger logger = LoggerFactory.getLogger(VirtualThreadMonitoringSystem.class);

    // 活动虚拟线程计数
    private static final AtomicInteger activeVirtualThreads = new AtomicInteger();

    // 线程固定事件计数
    private static final Map<String, AtomicInteger> pinnedThreadsByReason = new ConcurrentHashMap<>();

    // Micrometer指标
    private static final Counter virtualThreadCreatedCounter =
        Metrics.counter("vthread.created", "type", "virtual");

    private static final Counter virtualThreadCompletedCounter =
        Metrics.counter("vthread.completed", "type", "virtual");

    private static final Counter virtualThreadPinnedCounter =
        Metrics.counter("vthread.pinned", "type", "virtual");

    private static final Timer requestTimer =
        Metrics.timer("http.request.duration");

    static {
        // 注册虚拟线程活动数量指标
        Gauge.builder("vthread.active", activeVirtualThreads, AtomicInteger::get)
             .description("当前活动虚拟线程数量")
             .register(Metrics.globalRegistry);

        // 注册JVM内存使用指标
        Gauge.builder("jvm.memory.used",
                    () -> Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())
             .description("JVM内存使用量")
             .baseUnit("bytes")
             .register(Metrics.globalRegistry);
    }

    /**
     * 记录虚拟线程创建
     */
    public static void recordThreadCreated() {
        activeVirtualThreads.incrementAndGet();
        virtualThreadCreatedCounter.increment();
    }

    /**
     * 记录虚拟线程完成
     */
    public static void recordThreadCompleted() {
        activeVirtualThreads.decrementAndGet();
        virtualThreadCompletedCounter.increment();
    }

    /**
     * 记录虚拟线程固定事件
     * @param reason 固定原因
     */
    public static void recordThreadPinned(String reason) {
        virtualThreadPinnedCounter.increment();
        pinnedThreadsByReason.computeIfAbsent(reason, k -> new AtomicInteger()).incrementAndGet();

        if (logger.isWarnEnabled()) {
            logger.warn("检测到虚拟线程固定,原因: {}", reason);
        }
    }

    /**
     * 记录请求处理时间
     * @param durationMs 请求处理毫秒数
     */
    public static void recordRequestDuration(long durationMs) {
        requestTimer.record(Duration.ofMillis(durationMs));
    }

    /**
     * 获取线程固定统计信息
     */
    public static Map<String, Integer> getPinningStatistics() {
        Map<String, Integer> result = new HashMap<>();
        pinnedThreadsByReason.forEach((reason, count) -> result.put(reason, count.get()));
        return result;
    }

    /**
     * 启动JFR事件监控
     */
    public static void startJfrMonitoring() {
        RecordingStream rs = new RecordingStream();

        rs.enable("jdk.VirtualThreadStart");
        rs.enable("jdk.VirtualThreadEnd");
        rs.enable("jdk.VirtualThreadPinned");

        rs.onEvent("jdk.VirtualThreadStart", event -> {
            recordThreadCreated();
        });

        rs.onEvent("jdk.VirtualThreadEnd", event -> {
            recordThreadCompleted();
        });

        rs.onEvent("jdk.VirtualThreadPinned", event -> {
            String reason = event.getString("reason", "unknown");
            long duration = event.getDuration().toMillis();

            if (duration > 100) { // 仅记录长时间固定
                recordThreadPinned(reason);
            }
        });

        rs.start();
    }
}

11. 与其他并发模型对比

11.1 Java 虚拟线程 vs Golang Goroutines

特性Java 虚拟线程Golang Goroutines
实现方式JVM 管理的用户态线程Go 运行时管理的协程
内存占用~2KB/线程~2KB/协程
调度模型协作式调度协作+抢占式混合
上下文共享ThreadLocalContext 包
并发原语java.util.concurrentChannels, Select
阻塞处理挂起点自动检测编译器自动转换
生态系统兼容已有 Java 库需要特定 Go 库支持

11.2 虚拟线程 vs 响应式编程

特性虚拟线程响应式编程(Reactive)
编程模型命令式,直观声明式,函数式
调试难度简单,与传统线程相似复杂,特别是嵌套操作
学习曲线低,熟悉线程模型即可高,需学习新范式
代码迁移简单替换线程池需大量重构
背压控制需手动实现内置支持
性能开销低内存,高并发低内存,事件驱动
适用场景广泛,尤其 I/O 密集型事件流处理,高响应性要求

11.3 虚拟线程与 CompletableFuture 结合

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class VirtualThreadWithCompletableFuture {
    private static final Logger logger = LoggerFactory.getLogger(VirtualThreadWithCompletableFuture.class);

    public static void main(String[] args) {
        List<String> urls = List.of(
            "https://example.com",
            "https://example.org",
            "https://example.net"
        );

        // 创建虚拟线程执行器
        var executor = Executors.newVirtualThreadPerTaskExecutor();

        try {
            // 使用虚拟线程执行器运行CompletableFuture任务
            List<CompletableFuture<String>> futures = urls.stream()
                .map(url -> CompletableFuture.supplyAsync(() -> {
                    try {
                        logger.info("处理URL: {}", url);
                        // 模拟HTTP请求
                        Thread.sleep(100);
                        return "结果: " + url;
                    } catch (Exception e) {
                        logger.error("处理{}时出错", url, e);
                        return "错误: " + url;
                    }
                }, executor))
                .collect(Collectors.toList());

            // 等待所有CompletableFuture完成
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

            // 获取结果
            List<String> results = futures.stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList());

            results.forEach(logger::info);
        } finally {
            executor.shutdown();
        }
    }

    // 实际应用场景:组合CompletableFuture和虚拟线程
    public static List<ProductInfo> fetchProductsEnhanced(List<String> productIds) {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            // 1. 为每个产品ID创建异步任务
            List<CompletableFuture<ProductInfo>> productFutures = productIds.stream()
                .map(id -> CompletableFuture.supplyAsync(() -> {
                    // 获取基本产品信息
                    ProductInfo info = fetchBasicProductInfo(id);

                    // 2. 为每个产品并行获取额外信息
                    CompletableFuture<List<Review>> reviewsFuture =
                        CompletableFuture.supplyAsync(() -> fetchReviews(id), executor);

                    CompletableFuture<PriceInfo> priceFuture =
                        CompletableFuture.supplyAsync(() -> fetchPriceInfo(id), executor);

                    CompletableFuture<InventoryStatus> inventoryFuture =
                        CompletableFuture.supplyAsync(() -> fetchInventoryStatus(id), executor);

                    // 3. 组合所有信息
                    try {
                        info.setReviews(reviewsFuture.get());
                        info.setPriceInfo(priceFuture.get());
                        info.setInventory(inventoryFuture.get());
                    } catch (Exception e) {
                        logger.error("获取产品{}详情时出错", id, e);
                    }

                    return info;
                }, executor))
                .collect(Collectors.toList());

            // 4. 等待所有产品信息完成
            return productFutures.stream()
                .map(future -> {
                    try {
                        return future.get();
                    } catch (Exception e) {
                        logger.error("获取产品信息失败", e);
                        return null;
                    }
                })
                .filter(p -> p != null)
                .collect(Collectors.toList());
        }
    }

    // 模拟方法...
    private static ProductInfo fetchBasicProductInfo(String id) { return null; }
    private static List<Review> fetchReviews(String id) { return null; }
    private static PriceInfo fetchPriceInfo(String id) { return null; }
    private static InventoryStatus fetchInventoryStatus(String id) { return null; }

    // 数据类...
    static class ProductInfo {
        void setReviews(List<Review> reviews) {}
        void setPriceInfo(PriceInfo price) {}
        void setInventory(InventoryStatus status) {}
    }
    static class Review {}
    static class PriceInfo {}
    static class InventoryStatus {}
}

术语

术语英文描述
虚拟线程Virtual Thread由 JVM 管理的轻量级线程实现
承载线程Carrier Thread执行虚拟线程代码的操作系统线程
线程固定Thread Pinning虚拟线程因某些操作无法挂起,占用承载线程
挂起点Yield Point虚拟线程可以挂起的代码位置
结构化并发Structured Concurrency管理线程生命周期的编程模型
M:N 调度M:N Scheduling多个虚拟线程映射到少量平台线程的模型
协作式调度Cooperative Scheduling线程主动让出 CPU 的调度模型
延续Continuation捕获和恢复执行状态的底层机制
栈帧快照Stack Frame Snapshot保存虚拟线程挂起时的执行状态
背压Backpressure控制请求处理速率的机制
熔断器Circuit Breaker防止系统级联故障的保护机制
映射诊断上下文MDC (Mapped Diagnostic Context)为日志添加线程上下文信息的机制

总结

类别要点
基本概念• 轻量级线程实现
• JVM 管理而非 OS
• 协作式调度
• JDK 21 正式特性
工作原理• M:N 线程模型
• 基于延续的挂起/恢复
• 共享承载线程池
• 内存高效栈帧存储
最佳使用场景• I/O 密集型应用
• 高并发网络服务
• 大量短任务处理
• 微服务架构
创建方法• Thread.startVirtualThread()
• Thread.ofVirtual().start()
• Executors.newVirtualThreadPerTaskExecutor()
性能优势• 极低内存占用(~2KB/线程)
• 支持百万级并发
• 减少上下文切换开销
• 显著提升吞吐量
避免问题• 减少 synchronized 使用
• 规避线程固定
• 谨慎使用 ThreadLocal
• 监控原生方法交互
最佳方法• 使用 ExecutorService 管理生命周期
• 结合非阻塞 API
• 实施适当监控
• 优化数据库交互
• 实现适当背压控制
容器部署• 合理设置 CPU 和内存限制
• 优雅关闭处理
• 使用适当健康检查
• 监控虚拟线程状态

参考资料