Spring Boot 3.x虚拟线程(Virtual Thread)集成配置问题详解与解决方案

一、问题背景与概述

1.1 虚拟线程简介

Java 19引入的虚拟线程(Virtual Threads)是轻量级线程,由JVM管理而非操作系统:

// 传统平台线程
Thread platformThread = new Thread(() -> {
    System.out.println("Platform thread: " + Thread.currentThread());
});

// 虚拟线程
Thread virtualThread = Thread.startVirtualThread(() -> {
    System.out.println("Virtual thread: " + Thread.currentThread());
});

1.2 Spring Boot 3.x集成问题

主要问题表现

  1. Tomcat/Jetty容器配置问题
  2. 数据库连接池不兼容
  3. ThreadLocal/InheritableThreadLocal失效
  4. MDC日志上下文丢失
  5. 事务管理异常
  6. Reactive与虚拟线程冲突
  7. 监控和调试困难

二、Web容器虚拟线程配置问题

2.1 Tomcat虚拟线程配置

问题现象

# application.yml - 错误配置示例
server:
  tomcat:
    threads:
      max: 200
      min-spare: 10
  # 虚拟线程配置缺失

错误信息

WARNING: Virtual threads not enabled for Tomcat
解决方案:
// 方案1:通过配置类启用Tomcat虚拟线程
@Configuration
public class TomcatVirtualThreadConfig {
    
    @Bean
    public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadCustomizer() {
        return protocolHandler -> {
            // 关键配置:使用虚拟线程执行器
            protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
            
            // 优化虚拟线程池配置
            if (protocolHandler instanceof AbstractHttp11Protocol<?> http11) {
                // 调整连接器参数
                http11.setMaxConnections(10000);  // 提高最大连接数
                http11.setMaxThreads(1000);       // 虚拟线程下可设置更高
                http11.setConnectionTimeout(30000);
                http11.setKeepAliveTimeout(60000);
                http11.setMaxKeepAliveRequests(100);
            }
        };
    }
    
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
        return factory -> {
            factory.addConnectorCustomizers(connector -> {
                // 设置连接器属性
                connector.setProperty("maxThreads", "1000");
                connector.setProperty("acceptorThreadCount", "2");
                connector.setProperty("minSpareThreads", "5");
                
                // 启用虚拟线程特性
                connector.setProperty("useVirtualThreads", "true");
                connector.setProperty("virtualThreadKeepAlive", "60");
            });
            
            // 优化Tomcat配置
            factory.addContextCustomizers(context -> {
                context.setSessionTimeout(30);
                context.setBackgroundProcessorDelay(10);
            });
        };
    }
}

// 方案2:完整的Tomcat虚拟线程工厂配置
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
public class FullTomcatVirtualThreadConfig {
    
    @Value("${server.tomcat.virtual-threads.max-pool-size:1000}")
    private int maxPoolSize;
    
    @Value("${server.tomcat.virtual-threads.keep-alive-seconds:60}")
    private int keepAliveSeconds;
    
    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        
        factory.addConnectorCustomizers(connector -> {
            ProtocolHandler handler = connector.getProtocolHandler();
            
            if (handler instanceof AbstractHttp11Protocol<?> http11) {
                // 虚拟线程专用配置
                configureForVirtualThreads(http11);
            }
        });
        
        return factory;
    }
    
    private void configureForVirtualThreads(AbstractHttp11Protocol<?> protocol) {
        // 创建虚拟线程执行器
        ExecutorService virtualThreadExecutor = createVirtualThreadExecutor();
        protocol.setExecutor(virtualThreadExecutor);
        
        // 优化协议参数
        protocol.setMaxConnections(10000);
        protocol.setConnectionTimeout(30000);
        protocol.setConnectionUploadTimeout(60000);
        protocol.setDisableUploadTimeout(false);
        protocol.setKeepAliveTimeout(60000);
        protocol.setMaxKeepAliveRequests(100);
        protocol.setMaxSwallowSize(2097152); // 2MB
        protocol.setUseSendfile(true);
        
        // SSL优化
        protocol.setSSLEnabled(true);
        protocol.setSSLProtocol("TLSv1.2+TLSv1.3");
        protocol.setUseServerCipherSuitesOrder(true);
        
        // 压缩配置
        protocol.setCompression("on");
        protocol.setCompressionMinSize(2048);
        protocol.setCompressableMimeType(
            "text/html,text/xml,text/plain,text/css,text/javascript," +
            "application/javascript,application/json,application/xml");
    }
    
    private ExecutorService createVirtualThreadExecutor() {
        ThreadFactory virtualThreadFactory = Thread.ofVirtual()
            .name("tomcat-virtual-", 0)
            .factory();
        
        // 使用虚拟线程工厂
        return Executors.newThreadPerTaskExecutor(virtualThreadFactory);
    }
}

// 方案3:YAML配置配合代码
# application.yml
server:
  port: 8080
  tomcat:
    virtual-threads:
      enabled: true
      max-pool-size: 1000
      keep-alive-seconds: 60
      thread-name-prefix: "tomcat-vt-"
    connection-timeout: 30s
    max-connections: 10000
    keep-alive:
      timeout: 60s
      max-requests: 100
    compression:
      enabled: true
      min-response-size: 2KB
      mime-types: 
        - text/html
        - text/xml
        - text/plain
        - text/css
        - application/json
    accesslog:
      enabled: true
      pattern: "%t %a %r %s %D %{User-Agent}i"

2.2 Jetty虚拟线程配置

@Configuration
@ConditionalOnClass(org.eclipse.jetty.server.Server.class)
public class JettyVirtualThreadConfig {
    
    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
        
        factory.addServerCustomizers(server -> {
            // 配置Jetty使用虚拟线程
            QueuedThreadPool threadPool = new QueuedThreadPool();
            threadPool.setVirtualThreadsExecutor(Executors.newVirtualThreadPerTaskExecutor());
            threadPool.setMaxThreads(1000);
            threadPool.setMinThreads(10);
            threadPool.setIdleTimeout(60000);
            
            server.setThreadPool(threadPool);
            
            // 优化连接器
            for (Connector connector : server.getConnectors()) {
                if (connector instanceof ServerConnector serverConnector) {
                    configureJettyConnector(serverConnector);
                }
            }
        });
        
        return factory;
    }
    
    private void configureJettyConnector(ServerConnector connector) {
        HttpConfiguration httpConfig = connector.getConnectionFactory(
            HttpConnectionFactory.class).getHttpConfiguration();
        
        // 优化HTTP配置
        httpConfig.setRequestHeaderSize(8192);
        httpConfig.setResponseHeaderSize(8192);
        httpConfig.setSendServerVersion(false);
        httpConfig.setSendDateHeader(true);
        httpConfig.setHeaderCacheSize(512);
        
        // 连接器参数
        connector.setAcceptQueueSize(1024);
        connector.setIdleTimeout(30000);
        
        // SSL配置
        SslConnectionFactory sslConnFactory = connector.getConnectionFactory(
            SslConnectionFactory.class);
        if (sslConnFactory != null) {
            SslContextFactory.Server sslContextFactory = 
                (SslContextFactory.Server) sslConnFactory.getSslContextFactory();
            sslContextFactory.setExcludeCipherSuites(
                "SSL_RSA_WITH_DES_CBC_SHA",
                "SSL_DHE_RSA_WITH_DES_CBC_SHA",
                "SSL_DHE_DSS_WITH_DES_CBC_SHA"
            );
        }
    }
}

三、数据库连接池问题

3.1 HikariCP虚拟线程兼容性问题

问题现象

WARNING: HikariPool-1 - Connection is not available, request timed out after 30000ms.
解决方案:
// 方案1:优化HikariCP配置
@Configuration
public class HikariVirtualThreadConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariDataSource dataSource(DataSourceProperties properties) {
        HikariConfig config = new HikariConfig();
        
        // 虚拟线程优化配置
        config.setJdbcUrl(properties.getUrl());
        config.setUsername(properties.getUsername());
        config.setPassword(properties.getPassword());
        config.setDriverClassName(properties.getDriverClassName());
        
        // 关键:调整连接池参数适应虚拟线程
        config.setMaximumPoolSize(100);           // 虚拟线程下可减少
        config.setMinimumIdle(10);                // 最小空闲连接
        config.setConnectionTimeout(30000);       // 连接超时
        config.setIdleTimeout(600000);           // 空闲超时10分钟
        config.setMaxLifetime(1800000);          // 最大生命周期30分钟
        config.setKeepaliveTime(30000);          // 保活时间
        
        // 虚拟线程专用优化
        config.addDataSourceProperty("useVirtualThreads", "true");
        config.addDataSourceProperty("prepStmtCacheSize", 250);
        config.addDataSourceProperty("prepStmtCacheSqlLimit", 2048);
        config.addDataSourceProperty("cachePrepStmts", true);
        config.addDataSourceProperty("useServerPrepStmts", true);
        
        // 监控相关
        config.setMetricRegistry(null);  // 虚拟线程下可能不需要
        config.setHealthCheckRegistry(null);
        
        // 泄漏检测
        config.setLeakDetectionThreshold(60000);
        
        return new HikariDataSource(config);
    }
}

// 方案2:使用虚拟线程感知的连接池包装器
@Component
public class VirtualThreadAwareDataSource implements DataSource {
    
    private final DataSource delegate;
    private final ExecutorService virtualThreadExecutor;
    
    public VirtualThreadAwareDataSource(DataSource delegate) {
        this.delegate = delegate;
        this.virtualThreadExecutor = Executors.newVirtualThreadPerTaskExecutor();
    }
    
    @Override
    public Connection getConnection() throws SQLException {
        // 在虚拟线程中获取连接
        try {
            return virtualThreadExecutor.submit(delegate::getConnection).get();
        } catch (InterruptedException | ExecutionException e) {
            throw new SQLException("Failed to get connection in virtual thread", e);
        }
    }
    
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        // 类似实现
        return delegate.getConnection(username, password);
    }
    
    // 其他DataSource方法实现...
    
    @PreDestroy
    public void shutdown() {
        virtualThreadExecutor.shutdown();
    }
}

// 方案3:配置属性文件
# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db?useSSL=false&serverTimezone=UTC
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 50                # 虚拟线程下可以减少
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      pool-name: VirtualThreadPool
      leak-detection-threshold: 60000
      connection-test-query: SELECT 1
      data-source-properties:
        useVirtualThreads: true
        cachePrepStmts: true
        prepStmtCacheSize: 250
        prepStmtCacheSqlLimit: 2048
        useServerPrepStmts: true
        useLocalSessionState: true
        rewriteBatchedStatements: true
        maintainTimeStats: false
        cacheResultSetMetadata: true
        cacheServerConfiguration: true
        elideSetAutoCommits: true

3.2 事务管理问题

// 虚拟线程下的事务管理
@Configuration
@EnableTransactionManagement
public class VirtualThreadTransactionConfig {
    
    @Bean
    public PlatformTransactionManager transactionManager(
            EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        
        // 虚拟线程优化
        transactionManager.setNestedTransactionAllowed(true);
        transactionManager.setValidateExistingTransaction(true);
        transactionManager.setGlobalRollbackOnParticipationFailure(false);
        
        return transactionManager;
    }
    
    @Bean
    public TransactionTemplate transactionTemplate(
            PlatformTransactionManager transactionManager) {
        TransactionTemplate template = new TransactionTemplate(transactionManager);
        
        // 配置虚拟线程友好的事务属性
        template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        template.setTimeout(30); // 秒
        template.setReadOnly(false);
        
        return template;
    }
    
    // 虚拟线程感知的事务拦截器
    @Bean
    public TransactionInterceptor transactionInterceptor(
            PlatformTransactionManager transactionManager) {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionManager(transactionManager);
        
        // 配置事务属性源
        NameMatchTransactionAttributeSource source = 
            new NameMatchTransactionAttributeSource();
        
        Properties props = new Properties();
        props.setProperty("get*", "PROPAGATION_SUPPORTS,readOnly");
        props.setProperty("find*", "PROPAGATION_SUPPORTS,readOnly");
        props.setProperty("*", "PROPAGATION_REQUIRED,-Exception");
        
        source.setProperties(props);
        interceptor.setTransactionAttributeSource(source);
        
        return interceptor;
    }
}

四、ThreadLocal和上下文传递问题

4.1 MDC日志上下文丢失问题

问题现象

@Slf4j
@Component
public class LoggingService {
    
    public void process() {
        MDC.put("requestId", UUID.randomUUID().toString());
        
        Thread.startVirtualThread(() -> {
            // ❌ MDC上下文丢失
            log.info("Processing in virtual thread");
        });
    }
}
解决方案:
// 方案1:虚拟线程感知的MDC包装器
@Component
public class VirtualThreadMDC {
    
    private static final ThreadLocal<Map<String, String>> VIRTUAL_THREAD_CONTEXT =
        new ThreadLocal<>();
    
    public static void wrap(Runnable task) {
        Map<String, String> context = MDC.getCopyOfContextMap();
        
        Thread virtualThread = Thread.ofVirtual().start(() -> {
            if (context != null) {
                MDC.setContextMap(context);
            }
            try {
                task.run();
            } finally {
                MDC.clear();
            }
        });
    }
    
    public static <T> CompletableFuture<T> wrapAsync(Supplier<T> supplier) {
        Map<String, String> context = MDC.getCopyOfContextMap();
        
        return CompletableFuture.supplyAsync(() -> {
            if (context != null) {
                MDC.setContextMap(context);
            }
            try {
                return supplier.get();
            } finally {
                MDC.clear();
            }
        }, Executors.newVirtualThreadPerTaskExecutor());
    }
    
    // 增强版:支持结构化日志
    public static StructuredTaskWrapper structured() {
        return new StructuredTaskWrapper();
    }
    
    public static class StructuredTaskWrapper {
        private final Map<String, Object> attributes = new HashMap<>();
        
        public StructuredTaskWrapper attribute(String key, Object value) {
            attributes.put(key, value);
            return this;
        }
        
        public void run(Runnable task) {
            Map<String, String> mdcContext = MDC.getCopyOfContextMap();
            
            Thread.startVirtualThread(() -> {
                // 设置MDC
                if (mdcContext != null) {
                    MDC.setContextMap(mdcContext);
                }
                
                // 添加结构化属性
                try (var scope = new StructuredTaskScope()) {
                    // 执行任务
                    task.run();
                } catch (Exception e) {
                    log.error("Virtual thread task failed", e);
                } finally {
                    MDC.clear();
                }
            });
        }
    }
}

// 使用示例
@Service
public class LoggingService {
    
    @Autowired
    private VirtualThreadMDC mdcWrapper;
    
    public void processWithContext() {
        MDC.put("requestId", "req-123");
        MDC.put("userId", "user-456");
        
        // 正确传递MDC
        mdcWrapper.wrap(() -> {
            log.info("Processing with preserved MDC context");
            
            // 嵌套虚拟线程
            mdcWrapper.wrap(() -> {
                log.info("Nested virtual thread with context");
            });
        });
    }
}

// 方案2:AOP切面自动管理MDC
@Aspect
@Component
public class VirtualThreadMDCAspect {
    
    @Around("@annotation(WithVirtualThread)")
    public Object manageMDC(ProceedingJoinPoint joinPoint) throws Throwable {
        Map<String, String> context = MDC.getCopyOfContextMap();
        
        return CompletableFuture.supplyAsync(() -> {
            try {
                // 恢复MDC
                if (context != null) {
                    MDC.setContextMap(context);
                }
                
                // 添加方法信息
                MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                MDC.put("method", signature.getMethod().getName());
                MDC.put("class", joinPoint.getTarget().getClass().getSimpleName());
                
                return joinPoint.proceed();
            } catch (Throwable e) {
                throw new RuntimeException(e);
            } finally {
                MDC.clear();
            }
        }, Executors.newVirtualThreadPerTaskExecutor()).join();
    }
}

// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WithVirtualThread {
    String context() default "";
}

// 使用注解
@Service
public class AsyncService {
    
    @WithVirtualThread
    public CompletableFuture<String> processAsync(String input) {
        log.info("Processing in virtual thread with MDC");
        return CompletableFuture.completedFuture("Processed: " + input);
    }
}

4.2 请求上下文传递问题

// 方案:虚拟线程感知的RequestContextHolder
@Component
public class VirtualThreadRequestContext {
    
    private static final ThreadLocal<RequestAttributes> VIRTUAL_THREAD_REQUEST =
        new ThreadLocal<>();
    
    /**
     * 包装虚拟线程任务,传递请求上下文
     */
    public static Runnable wrapWithContext(Runnable task) {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        
        return () -> {
            try {
                // 设置请求上下文
                if (attributes != null) {
                    RequestContextHolder.setRequestAttributes(attributes, true);
                }
                
                task.run();
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        };
    }
    
    /**
     * 异步执行并传递上下文
     */
    public static <T> CompletableFuture<T> supplyAsyncWithContext(
            Supplier<T> supplier) {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        
        return CompletableFuture.supplyAsync(() -> {
            try {
                if (attributes != null) {
                    RequestContextHolder.setRequestAttributes(attributes, true);
                }
                return supplier.get();
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        }, Executors.newVirtualThreadPerTaskExecutor());
    }
    
    /**
     * 创建虚拟线程作用域
     */
    public static VirtualThreadScope createScope() {
        return new VirtualThreadScope();
    }
    
    public static class VirtualThreadScope implements AutoCloseable {
        private final Map<Class<?>, Object> beans = new HashMap<>();
        private final RequestAttributes originalAttributes;
        
        public VirtualThreadScope() {
            this.originalAttributes = RequestContextHolder.getRequestAttributes();
        }
        
        public <T> T getOrCreate(Class<T> type, Supplier<T> creator) {
            return type.cast(beans.computeIfAbsent(type, k -> creator.get()));
        }
        
        public void runInScope(Runnable task) {
            Thread.startVirtualThread(() -> {
                try {
                    // 设置请求上下文
                    if (originalAttributes != null) {
                        RequestContextHolder.setRequestAttributes(
                            originalAttributes, true);
                    }
                    
                    // 执行任务
                    task.run();
                } finally {
                    RequestContextHolder.resetRequestAttributes();
                    beans.clear();
                }
            });
        }
        
        @Override
        public void close() {
            beans.clear();
        }
    }
}

// 拦截器:自动传递请求上下文
@Component
public class VirtualThreadContextInterceptor implements AsyncHandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) {
        // 在虚拟线程中存储请求属性
        request.setAttribute("virtualThreadContext", 
            RequestContextHolder.getRequestAttributes());
        return true;
    }
    
    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request,
                                             HttpServletResponse response,
                                             Object handler) {
        // 异步处理开始
    }
}

// 配置拦截器
@Configuration
public class WebMvcVirtualThreadConfig implements WebMvcConfigurer {
    
    @Autowired
    private VirtualThreadContextInterceptor contextInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(contextInterceptor)
            .addPathPatterns("/api/**");
    }
}

五、异步任务与虚拟线程集成

5.1 @Async虚拟线程配置

@Configuration
@EnableAsync
public class VirtualThreadAsyncConfig implements AsyncConfigurer {
    
    @Value("${async.virtual-threads.core-pool-size:100}")
    private int corePoolSize;
    
    @Value("${async.virtual-threads.max-pool-size:1000}")
    private int maxPoolSize;
    
    @Value("${async.virtual-threads.keep-alive-seconds:60}")
    private int keepAliveSeconds;
    
    @Override
    public Executor getAsyncExecutor() {
        // 创建虚拟线程执行器
        ThreadFactory virtualThreadFactory = Thread.ofVirtual()
            .name("async-vt-", 0)
            .factory();
        
        // 使用虚拟线程执行器
        ExecutorService executor = Executors.newThreadPerTaskExecutor(virtualThreadFactory);
        
        return new DelegatingExecutor(executor) {
            @Override
            public void execute(Runnable task) {
                // 包装任务以传递上下文
                Runnable wrappedTask = VirtualThreadRequestContext.wrapWithContext(task);
                super.execute(wrappedTask);
            }
        };
    }
    
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> {
            log.error("Async method {} failed", method.getName(), ex);
            
            // 虚拟线程特定的异常处理
            if (ex instanceof VirtualThreadException) {
                handleVirtualThreadException((VirtualThreadException) ex);
            }
        };
    }
    
    // 虚拟线程感知的TaskExecutor
    @Bean(name = "virtualThreadTaskExecutor")
    public TaskExecutor virtualThreadTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        
        // 配置虚拟线程执行器
        executor.setThreadFactory(Thread.ofVirtual()
            .name("task-vt-", 0)
            .factory());
        
        // 由于使用虚拟线程,以下参数意义不同
        executor.setCorePoolSize(1);      // 虚拟线程下可设置为1
        executor.setMaxPoolSize(Integer.MAX_VALUE); // 虚拟线程无上限
        executor.setQueueCapacity(0);     // 虚拟线程不使用队列
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(30);
        executor.setThreadNamePrefix("task-vt-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.initialize();
        
        return executor;
    }
    
    // 调度任务虚拟线程支持
    @Bean
    public TaskScheduler virtualThreadTaskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        
        scheduler.setThreadFactory(Thread.ofVirtual()
            .name("scheduler-vt-", 0)
            .factory());
        
        scheduler.setPoolSize(10);  // 调度线程数
        scheduler.setThreadNamePrefix("scheduler-vt-");
        scheduler.setAwaitTerminationSeconds(30);
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        scheduler.initialize();
        
        return scheduler;
    }
}

// 使用@Async的改进版
@Service
public class AsyncVirtualThreadService {
    
    @Async("virtualThreadTaskExecutor")
    @VirtualThreadContext  // 自定义注解
    public CompletableFuture<String> processAsync(String input) {
        // 在虚拟线程中执行,上下文已自动传递
        log.info("Processing in virtual thread: {}", input);
        
        // 模拟耗时操作
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        return CompletableFuture.completedFuture("Processed: " + input);
    }
    
    // 批量虚拟线程处理
    public CompletableFuture<List<String>> processBatch(List<String> inputs) {
        List<CompletableFuture<String>> futures = inputs.stream()
            .map(this::processAsync)
            .collect(Collectors.toList());
        
        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .thenApply(v -> futures.stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList()));
    }
}

// 自定义注解处理器
@Aspect
@Component
public class VirtualThreadContextAspect {
    
    @Around("@annotation(virtualThreadContext)")
    public Object handleVirtualThreadContext(ProceedingJoinPoint joinPoint,
                                            VirtualThreadContext virtualThreadContext)
            throws Throwable {
        
        // 获取当前上下文
        Map<String, String> mdcContext = MDC.getCopyOfContextMap();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        
        // 在虚拟线程中执行
        return CompletableFuture.supplyAsync(() -> {
            try {
                // 恢复上下文
                if (mdcContext != null) {
                    MDC.setContextMap(mdcContext);
                }
                if (requestAttributes != null) {
                    RequestContextHolder.setRequestAttributes(requestAttributes, true);
                }
                
                return joinPoint.proceed();
            } catch (Throwable e) {
                throw new RuntimeException(e);
            } finally {
                // 清理
                MDC.clear();
                RequestContextHolder.resetRequestAttributes();
            }
        }, Executors.newVirtualThreadPerTaskExecutor()).join();
    }
}

5.2 CompletableFuture虚拟线程支持

@Component
public class VirtualThreadCompletableFuture {
    
    private final ExecutorService virtualThreadExecutor;
    
    public VirtualThreadCompletableFuture() {
        // 创建虚拟线程执行器
        this.virtualThreadExecutor = Executors.newThreadPerTaskExecutor(
            Thread.ofVirtual()
                .name("cf-vt-", 0)
                .factory()
        );
    }
    
    /**
     * 在虚拟线程中执行Supplier
     */
    public <T> CompletableFuture<T> supplyAsync(Supplier<T> supplier) {
        return CompletableFuture.supplyAsync(() -> {
            // 自动管理MDC
            Map<String, String> mdcContext = MDC.getCopyOfContextMap();
            try {
                if (mdcContext != null) {
                    MDC.setContextMap(mdcContext);
                }
                return supplier.get();
            } finally {
                MDC.clear();
            }
        }, virtualThreadExecutor);
    }
    
    /**
     * 在虚拟线程中执行Runnable
     */
    public CompletableFuture<Void> runAsync(Runnable runnable) {
        return CompletableFuture.runAsync(() -> {
            Map<String, String> mdcContext = MDC.getCopyOfContextMap();
            try {
                if (mdcContext != null) {
                    MDC.setContextMap(mdcContext);
                }
                runnable.run();
            } finally {
                MDC.clear();
            }
        }, virtualThreadExecutor);
    }
    
    /**
     * 并行执行多个任务
     */
    public <T> CompletableFuture<List<T>> allOf(List<Supplier<T>> suppliers) {
        List<CompletableFuture<T>> futures = suppliers.stream()
            .map(this::supplyAsync)
            .collect(Collectors.toList());
        
        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .thenApply(v -> futures.stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList()));
    }
    
    /**
     * 带超时的虚拟线程执行
     */
    public <T> CompletableFuture<T> supplyAsyncWithTimeout(
            Supplier<T> supplier, long timeout, TimeUnit unit) {
        return supplyAsync(supplier)
            .orTimeout(timeout, unit)
            .exceptionally(ex -> {
                if (ex instanceof TimeoutException) {
                    log.warn("Virtual thread task timeout after {} {}", timeout, unit);
                    return null;
                }
                throw new CompletionException(ex);
            });
    }
    
    @PreDestroy
    public void shutdown() {
        virtualThreadExecutor.shutdown();
        try {
            if (!virtualThreadExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                virtualThreadExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            virtualThreadExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

六、监控和诊断配置

6.1 虚拟线程监控

@Component
@Slf4j
public class VirtualThreadMonitor {
    
    private final ScheduledExecutorService monitorScheduler;
    private final Map<String, VirtualThreadStats> threadStats = new ConcurrentHashMap<>();
    
    public VirtualThreadMonitor() {
        this.monitorScheduler = Executors.newScheduledThreadPool(1);
    }
    
    @PostConstruct
    public void startMonitoring() {
        // 每5秒收集一次虚拟线程统计信息
        monitorScheduler.scheduleAtFixedRate(() -> {
            try {
                collectVirtualThreadStats();
                logVirtualThreadMetrics();
                checkForProblems();
            } catch (Exception e) {
                log.error("Failed to collect virtual thread stats", e);
            }
        }, 5, 5, TimeUnit.SECONDS);
        
        // 注册JMX Bean
        registerJmxBean();
    }
    
    private void collectVirtualThreadStats() {
        Thread.getAllStackTraces().forEach((thread, stackTrace) -> {
            if (thread.isVirtual()) {
                String threadName = thread.getName();
                VirtualThreadStats stats = threadStats.computeIfAbsent(
                    threadName, k -> new VirtualThreadStats());
                
                stats.update(thread, stackTrace);
            }
        });
        
        // 清理过期的线程统计
        cleanupOldStats();
    }
    
    private void logVirtualThreadMetrics() {
        long virtualThreadCount = threadStats.size();
        long pinnedThreads = threadStats.values().stream()
            .filter(VirtualThreadStats::isPinned)
            .count();
        
        double avgCpuTime = threadStats.values().stream()
            .mapToLong(VirtualThreadStats::getCpuTime)
            .average()
            .orElse(0);
        
        log.info("Virtual Thread Metrics - Count: {}, Pinned: {}, Avg CPU: {}ms", 
            virtualThreadCount, pinnedThreads, avgCpuTime);
        
        // 详细统计
        if (log.isDebugEnabled()) {
            threadStats.forEach((name, stats) -> {
                log.debug("Thread {}: state={}, cpu={}ms, user={}ms", 
                    name, stats.getState(), stats.getCpuTime(), stats.getUserTime());
            });
        }
    }
    
    private void checkForProblems() {
        // 检查是否有线程被pin住
        threadStats.entrySet().stream()
            .filter(entry -> entry.getValue().isPinned())
            .forEach(entry -> {
                log.warn("Virtual thread {} is pinned! Stack trace:\n{}",
                    entry.getKey(), entry.getValue().getStackTrace());
            });
        
        // 检查CPU使用率过高的线程
        threadStats.entrySet().stream()
            .filter(entry -> entry.getValue().getCpuTime() > 1000) // 超过1秒
            .forEach(entry -> {
                log.warn("Virtual thread {} using high CPU: {}ms",
                    entry.getKey(), entry.getValue().getCpuTime());
            });
    }
    
    private void registerJmxBean() {
        try {
            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
            ObjectName name = new ObjectName("com.example:type=VirtualThreadMonitor");
            mbs.registerMBean(new VirtualThreadMonitorMXBean() {
                @Override
                public long getVirtualThreadCount() {
                    return threadStats.size();
                }
                
                @Override
                public long getPinnedThreadCount() {
                    return threadStats.values().stream()
                        .filter(VirtualThreadStats::isPinned)
                        .count();
                }
                
                @Override
                public Map<String, String> getThreadStates() {
                    return threadStats.entrySet().stream()
                        .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            e -> e.getValue().getState().toString()
                        ));
                }
            }, name);
        } catch (Exception e) {
            log.error("Failed to register JMX bean", e);
        }
    }
    
    @PreDestroy
    public void stopMonitoring() {
        monitorScheduler.shutdown();
    }
    
    private static class VirtualThreadStats {
        private Thread.State state;
        private long cpuTime;
        private long userTime;
        private boolean pinned;
        private StackTraceElement[] stackTrace;
        private long lastUpdateTime;
        
        void update(Thread thread, StackTraceElement[] stackTrace) {
            this.state = thread.getState();
            this.cpuTime = thread.isAlive() ? 
                ManagementFactory.getThreadMXBean().getThreadCpuTime(thread.getId()) / 1_000_000 : 0;
            this.userTime = thread.isAlive() ?
                ManagementFactory.getThreadMXBean().getThreadUserTime(thread.getId()) / 1_000_000 : 0;
            this.pinned = isThreadPinned(thread);
            this.stackTrace = stackTrace;
            this.lastUpdateTime = System.currentTimeMillis();
        }
        
        private boolean isThreadPinned(Thread thread) {
            // 简化实现:检查线程是否在某个状态停留过久
            return thread.getState() == Thread.State.RUNNABLE && 
                   cpuTime > 100; // 超过100ms可能是pin住
        }
        
        // Getters...
    }
    
    public interface VirtualThreadMonitorMXBean {
        long getVirtualThreadCount();
        long getPinnedThreadCount();
        Map<String, String> getThreadStates();
    }
}

6.2 Micrometer监控集成

@Configuration
public class VirtualThreadMetricsConfig {
    
    @Bean
    public MeterBinder virtualThreadMeterBinder() {
        return registry -> {
            // 虚拟线程数量
            Gauge.builder("jvm.virtual.threads.count", 
                    () -> Thread.getAllStackTraces().keySet().stream()
                        .filter(Thread::isVirtual)
                        .count())
                .description("Number of virtual threads")
                .tag("type", "virtual")
                .register(registry);
            
            // 平台线程数量
            Gauge.builder("jvm.platform.threads.count",
                    () -> Thread.getAllStackTraces().keySet().stream()
                        .filter(t -> !t.isVirtual())
                        .count())
                .description("Number of platform threads")
                .tag("type", "platform")
                .register(registry);
            
            // 虚拟线程状态分布
            for (Thread.State state : Thread.State.values()) {
                Gauge.builder("jvm.virtual.threads.state",
                        () -> Thread.getAllStackTraces().keySet().stream()
                            .filter(Thread::isVirtual)
                            .filter(t -> t.getState() == state)
                            .count())
                    .description("Virtual threads in state " + state)
                    .tag("state", state.name().toLowerCase())
                    .register(registry);
            }
            
            // 虚拟线程创建速率
            Counter.builder("jvm.virtual.threads.created")
                .description("Total virtual threads created")
                .register(registry);
            
            // CPU时间统计
            Timer.builder("jvm.virtual.threads.cpu.time")
                .description("CPU time used by virtual threads")
                .publishPercentiles(0.5, 0.95, 0.99)
                .register(registry);
        };
    }
    
    @Bean
    public TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
    }
    
    @Bean
    public CountedAspect countedAspect(MeterRegistry registry) {
        return new CountedAspect(registry);
    }
}

// 虚拟线程感知的指标收集
@Component
public class VirtualThreadMetricsCollector {
    
    private final MeterRegistry meterRegistry;
    private final Map<Long, Long> threadStartTimes = new ConcurrentHashMap<>();
    
    public VirtualThreadMetricsCollector(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // 注册虚拟线程创建监听器
        Thread.Builder virtualThreadBuilder = Thread.ofVirtual()
            .name("monitored-vt-", 0)
            .allowSetThreadLocals(true)
            .inheritInheritableThreadLocals(true);
            
        // 使用增强的ThreadFactory
        ThreadFactory monitoredFactory = runnable -> {
            Thread thread = virtualThreadBuilder.unstarted(runnable);
            
            // 记录线程创建
            Counter createdCounter = Counter.builder("jvm.virtual.threads.created")
                .tag("name", thread.getName())
                .register(meterRegistry);
            createdCounter.increment();
            
            threadStartTimes.put(thread.getId(), System.nanoTime());
            
            return thread;
        };
    }
    
    public void recordThreadCompletion(long threadId) {
        Long startTime = threadStartTimes.remove(threadId);
        if (startTime != null) {
            long duration = System.nanoTime() - startTime;
            
            Timer.Sample sample = Timer.start(meterRegistry);
            sample.stop(Timer.builder("jvm.virtual.threads.lifetime")
                .description("Virtual thread lifetime")
                .publishPercentiles(0.5, 0.95, 0.99)
                .register(meterRegistry));
        }
    }
}

七、最佳实践配置总结

7.1 完整配置示例

# application.yml - 虚拟线程完整配置
spring:
  application:
    name: virtual-thread-demo
  
  # 虚拟线程配置
  virtual-threads:
    enabled: true
    mode: hybrid  # hybrid|virtual-only|platform-only
    executor:
      core-pool-size: 1
      max-pool-size: 10000
      keep-alive-seconds: 60
      thread-name-prefix: "app-vt-"
    tomcat:
      enabled: true
      max-connections: 10000
      connection-timeout: 30s
    database:
      connection-pool:
        max-size: 50
        validation-query: "SELECT 1"
        leak-detection-threshold: 60s
  
  # 数据源配置
  datasource:
    hikari:
      maximum-pool-size: 50
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      data-source-properties:
        useVirtualThreads: true
        cachePrepStmts: true
        prepStmtCacheSize: 250
  
  # 异步配置
  task:
    execution:
      pool:
        core-size: 1
        max-size: 10000
        queue-capacity: 0
        keep-alive: 60s
        thread-name-prefix: "async-vt-"
    scheduling:
      pool:
        size: 10
        thread-name-prefix: "sched-vt-"
  
  # JPA配置
  jpa:
    properties:
      hibernate:
        connection.handling_mode: DELAYED_ACQUISITION_AND_HOLD
        jdbc.batch_size: 20
        order_inserts: true
        order_updates: true
  
  # 监控配置
  management:
    endpoints:
      web:
        exposure:
          include: health,info,metrics,prometheus,threaddump
    metrics:
      export:
        prometheus:
          enabled: true
      tags:
        application: ${spring.application.name}
        environment: ${ENV:local}
    endpoint:
      health:
        show-details: always

# 日志配置
logging:
  pattern:
    level: "%5p [${spring.application.name},%X{traceId:-},%X{spanId:-},%thread]"
  level:
    org.springframework: INFO
    com.example: DEBUG

# 虚拟线程性能调优
virtual-thread-tuning:
  pinning-threshold-ms: 100
  stack-size-kb: 1024
  carrier-thread-count: ${CPU_COUNT:8}
  monitor-enabled: true
  monitor-interval-ms: 5000

7.2 主配置类

@SpringBootApplication
@EnableAsync
@EnableScheduling
@EnableTransactionManagement
@EnableConfigurationProperties({
    VirtualThreadProperties.class,
    VirtualThreadTuningProperties.class
})
public class VirtualThreadApplication {
    
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(VirtualThreadApplication.class);
        
        // 设置虚拟线程相关的系统属性
        System.setProperty("spring.threads.virtual.enabled", "true");
        System.setProperty("jdk.virtualThreadScheduler.parallelism", 
            String.valueOf(Runtime.getRuntime().availableProcessors()));
        System.setProperty("jdk.virtualThreadScheduler.maxPoolSize", "256");
        
        app.run(args);
    }
    
    @Bean
    public CommandLineRunner virtualThreadInfo() {
        return args -> {
            log.info("Virtual threads enabled: {}", 
                Thread.currentThread().isVirtual() || 
                ManagementFactory.getThreadMXBean().isVirtualThreadsSupported());
            
            log.info("Available processors: {}", 
                Runtime.getRuntime().availableProcessors());
            
            log.info("JVM version: {}", 
                System.getProperty("java.version"));
        };
    }
}

// 虚拟线程配置属性类
@ConfigurationProperties(prefix = "spring.virtual-threads")
@Data
public class VirtualThreadProperties {
    
    private boolean enabled = true;
    private Mode mode = Mode.HYBRID;
    private ExecutorConfig executor = new ExecutorConfig();
    private TomcatConfig tomcat = new TomcatConfig();
    private DatabaseConfig database = new DatabaseConfig();
    
    public enum Mode {
        HYBRID,      // 混合模式
        VIRTUAL_ONLY, // 仅虚拟线程
        PLATFORM_ONLY // 仅平台线程
    }
    
    @Data
    public static class ExecutorConfig {
        private int corePoolSize = 1;
        private int maxPoolSize = 10000;
        private int keepAliveSeconds = 60;
        private String threadNamePrefix = "app-vt-";
        private boolean allowCoreThreadTimeout = true;
        private boolean prestartAllCoreThreads = false;
    }
    
    @Data
    public static class TomcatConfig {
        private boolean enabled = true;
        private int maxConnections = 10000;
        private Duration connectionTimeout = Duration.ofSeconds(30);
        private int maxThreads = 1000;
        private int minSpareThreads = 10;
        private int acceptorThreadCount = 1;
    }
    
    @Data
    public static class DatabaseConfig {
        private ConnectionPool connectionPool = new ConnectionPool();
        
        @Data
        public static class ConnectionPool {
            private int maxSize = 50;
            private int minIdle = 5;
            private String validationQuery = "SELECT 1";
            private Duration leakDetectionThreshold = Duration.ofSeconds(60);
            private boolean cachePrepStmts = true;
            private int prepStmtCacheSize = 250;
        }
    }
}

7.3 健康检查

@Component
public class VirtualThreadHealthIndicator implements HealthIndicator {
    
    private final VirtualThreadMonitor monitor;
    private final VirtualThreadProperties properties;
    
    public VirtualThreadHealthIndicator(VirtualThreadMonitor monitor,
                                       VirtualThreadProperties properties) {
        this.monitor = monitor;
        this.properties = properties;
    }
    
    @Override
    public Health health() {
        if (!properties.isEnabled()) {
            return Health.up()
                .withDetail("enabled", false)
                .build();
        }
        
        try {
            long virtualThreadCount = Thread.getAllStackTraces().keySet().stream()
                .filter(Thread::isVirtual)
                .count();
            
            long pinnedThreads = Thread.getAllStackTraces().keySet().stream()
                .filter(Thread::isVirtual)
                .filter(this::isPinned)
                .count();
            
            Health.Builder builder = Health.up()
                .withDetail("virtualThreads.count", virtualThreadCount)
                .withDetail("virtualThreads.pinned", pinnedThreads)
                .withDetail("mode", properties.getMode().toString());
            
            // 检查是否有问题
            if (pinnedThreads > virtualThreadCount * 0.1) {
                // 超过10%的虚拟线程被pin住
                builder.down()
                    .withDetail("reason", "Too many pinned virtual threads")
                    .withDetail("pinnedPercentage", 
                        String.format("%.1f%%", (pinnedThreads * 100.0 / virtualThreadCount)));
            }
            
            return builder.build();
            
        } catch (Exception e) {
            return Health.down(e)
                .withDetail("error", e.getMessage())
                .build();
        }
    }
    
    private boolean isPinned(Thread thread) {
        // 简化实现:检查线程状态和CPU时间
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        long cpuTime = threadBean.getThreadCpuTime(thread.getId());
        
        return thread.getState() == Thread.State.RUNNABLE && 
               cpuTime > 100_000_000; // 100ms
    }
}

7.4 调试和故障排除

@Component
@ConditionalOnProperty(name = "virtual-thread-tuning.debug", havingValue = "true")
public class VirtualThreadDebugger {
    
    private final ThreadMXBean threadBean;
    private final Map<Long, ThreadDebugInfo> debugInfos = new ConcurrentHashMap<>();
    
    public VirtualThreadDebugger() {
        this.threadBean = ManagementFactory.getThreadMXBean();
        this.threadBean.setThreadContentionMonitoringEnabled(true);
        this.threadBean.setThreadCpuTimeEnabled(true);
    }
    
    public void startMonitoring(Thread thread) {
        if (thread.isVirtual()) {
            ThreadDebugInfo info = new ThreadDebugInfo(thread);
            debugInfos.put(thread.getId(), info);
            
            // 设置UncaughtExceptionHandler
            thread.setUncaughtExceptionHandler((t, e) -> {
                log.error("Virtual thread {} failed", t.getName(), e);
                debugInfos.remove(t.getId());
            });
        }
    }
    
    public void recordEvent(long threadId, String event, Object data) {
        ThreadDebugInfo info = debugInfos.get(threadId);
        if (info != null) {
            info.recordEvent(event, data);
        }
    }
    
    public void dumpDebugInfo() {
        debugInfos.forEach((id, info) -> {
            log.info("Thread {} ({}):", info.getThreadName(), info.getThreadId());
            log.info("  State: {}", info.getState());
            log.info("  CPU Time: {}ms", info.getCpuTime() / 1_000_000);
            log.info("  User Time: {}ms", info.getUserTime() / 1_000_000);
            log.info("  Blocked Count: {}", info.getBlockedCount());
            log.info("  Waited Count: {}", info.getWaitedCount());
            
            if (!info.getEvents().isEmpty()) {
                log.info("  Events:");
                info.getEvents().forEach((time, event) -> {
                    log.info("    {}: {}", time, event);
                });
            }
            
            // 栈轨迹
            if (log.isDebugEnabled()) {
                log.debug("  Stack Trace:");
                for (StackTraceElement element : info.getStackTrace()) {
                    log.debug("    {}", element);
                }
            }
        });
    }
    
    private static class ThreadDebugInfo {
        private final long threadId;
        private final String threadName;
        private final Thread thread;
        private final Map<Long, String> events = new LinkedHashMap<>();
        
        ThreadDebugInfo(Thread thread) {
            this.threadId = thread.getId();
            this.threadName = thread.getName();
            this.thread = thread;
        }
        
        void recordEvent(String event, Object data) {
            events.put(System.currentTimeMillis(), 
                event + (data != null ? ": " + data : ""));
        }
        
        // Getters...
    }
}

通过以上详细的配置和解决方案,可以有效地在Spring Boot 3.x中集成和使用虚拟线程,充分发挥其高并发优势,同时避免常见的集成问题。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐