Spring Boot 3.x.x + JDK 21 虚拟线程使用指南

吴书松
吴书松
发布于 2026-01-26 / 1 阅读
0
0

Spring Boot 3.x.x + JDK 21 虚拟线程使用指南

1. 环境要求与配置

1.1 依赖配置 (pom.xml)

xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>virtual-threads-demo</artifactId>
    <version>1.0.0</version>
    
    <properties>
        <java.version>21</java.version>
    </properties>
    
    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring Boot Actuator (监控) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        
        <!-- 数据库相关 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!-- 测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

1.2 application.yml 配置

yaml

server:
  port: 8080
  
spring:
  application:
    name: virtual-threads-demo
  
  # H2 数据库配置
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password: 
  
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect
        format_sql: true

# 虚拟线程配置
spring.threads:
  virtual:
    enabled: true  # 启用虚拟线程

# Actuator 端点配置
management:
  endpoints:
    web:
      exposure:
        include: health,metrics,threaddump
  metrics:
    tags:
      application: ${spring.application.name}

2. 虚拟线程基础配置

2.1 配置虚拟线程 Executor

java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

@Configuration
@EnableAsync
public class VirtualThreadConfig {
    
    /**
     * 创建虚拟线程池
     * 用于 @Async 注解
     */
    @Bean(name = "virtualThreadExecutor")
    public Executor virtualThreadExecutor() {
        return Executors.newVirtualThreadPerTaskExecutor();
    }
    
    /**
     * 创建用于 CPU 密集型任务的虚拟线程池
     * 限制并发数,避免过多线程竞争 CPU
     */
    @Bean(name = "cpuIntensiveExecutor")
    public Executor cpuIntensiveExecutor() {
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        return Executors.newThreadPerTaskExecutor(
            Thread.ofVirtual()
                .name("cpu-intensive-", 0)
                .factory()
        );
    }
}

2.2 虚拟线程监控器

java

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;

@Component
public class VirtualThreadHealthIndicator implements HealthIndicator {
    
    @Override
    public Health health() {
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        long totalThreads = threadBean.getThreadCount();
        long daemonThreads = threadBean.getDaemonThreadCount();
        
        // 统计虚拟线程(需要 JDK 21+)
        long virtualThreads = Thread.getAllStackTraces()
            .keySet()
            .stream()
            .filter(Thread::isVirtual)
            .count();
        
        return Health.up()
            .withDetail("total_threads", totalThreads)
            .withDetail("daemon_threads", daemonThreads)
            .withDetail("virtual_threads", virtualThreads)
            .withDetail("platform_threads", totalThreads - virtualThreads)
            .build();
    }
}

3. 虚拟线程在 Web 层的应用

3.1 REST Controller 使用虚拟线程

java

import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;

@Slf4j
@RestController
@RequestMapping("/api/virtual-threads")
public class VirtualThreadController {
    
    private final ExecutorService virtualThreadExecutor = 
        Executors.newVirtualThreadPerTaskExecutor();
    
    /**
     * 示例1: 简单的虚拟线程异步处理
     */
    @GetMapping("/hello")
    public CompletableFuture<String> helloAsync() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                // 模拟IO操作
                Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
                return "Hello from virtual thread: " + Thread.currentThread();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            }
        }, virtualThreadExecutor);
    }
    
    /**
     * 示例2: 并行处理多个IO操作
     */
    @GetMapping("/parallel-io")
    public CompletableFuture<ResponseEntity<?>> parallelIOOperations() {
        var future1 = CompletableFuture.supplyAsync(() -> {
            simulateIO("Database Query", 200);
            return "DB Result";
        }, virtualThreadExecutor);
        
        var future2 = CompletableFuture.supplyAsync(() -> {
            simulateIO("External API Call", 300);
            return "API Result";
        }, virtualThreadExecutor);
        
        var future3 = CompletableFuture.supplyAsync(() -> {
            simulateIO("File System Operation", 150);
            return "File Result";
        }, virtualThreadExecutor);
        
        return CompletableFuture.allOf(future1, future2, future3)
            .thenApply(v -> ResponseEntity.ok()
                .body(String.format("All operations completed: %s, %s, %s",
                    future1.join(), future2.join(), future3.join())));
    }
    
    /**
     * 示例3: 虚拟线程处理 WebClient 调用
     */
    @GetMapping("/webclient-example")
    public CompletableFuture<ResponseEntity<?>> webClientExample() {
        return CompletableFuture.supplyAsync(() -> {
            // 在实际应用中,这里会使用 WebClient 进行HTTP调用
            simulateIO("HTTP Request to external service", 400);
            return ResponseEntity.ok()
                .body(Map.of(
                    "status", "success",
                    "thread", Thread.currentThread().toString(),
                    "message", "WebClient call completed"
                ));
        }, virtualThreadExecutor);
    }
    
    private void simulateIO(String operation, int delayMillis) {
        log.info("{} starting on thread: {}", operation, Thread.currentThread());
        try {
            Thread.sleep(delayMillis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(e);
        }
        log.info("{} completed on thread: {}", operation, Thread.currentThread());
    }
}

4. Service 层使用虚拟线程

4.1 异步 Service 示例

java

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import lombok.RequiredArgsConstructor;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class VirtualThreadService {
    
    private final Map<Long, String> taskStore = new ConcurrentHashMap<>();
    
    /**
     * 使用 @Async 注解配合虚拟线程执行器
     */
    @Async("virtualThreadExecutor")
    public CompletableFuture<String> processTask(Long taskId) {
        log.info("Processing task {} on virtual thread: {}", 
            taskId, Thread.currentThread());
        
        // 模拟耗时IO操作
        simulateIOOperation(300);
        
        String result = "Task-" + taskId + "-completed";
        taskStore.put(taskId, result);
        
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 批量处理任务 - 每个任务在独立的虚拟线程中执行
     */
    public CompletableFuture<List<String>> processBatch(List<Long> taskIds) {
        List<CompletableFuture<String>> futures = taskIds.stream()
            .map(taskId -> CompletableFuture.supplyAsync(() -> {
                simulateIOOperation(200);
                String result = "Batch-Task-" + taskId;
                taskStore.put(taskId, result);
                return result;
            }, Executors.newVirtualThreadPerTaskExecutor()))
            .toList();
            
        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .thenApply(v -> futures.stream()
                .map(CompletableFuture::join)
                .toList());
    }
    
    /**
     * 模拟数据库操作的虚拟线程使用
     */
    @Async("virtualThreadExecutor")
    public CompletableFuture<List<User>> findUsersByName(String name) {
        return CompletableFuture.supplyAsync(() -> {
            // 在实际应用中,这里会调用 Repository
            simulateIOOperation("Database query for users: " + name, 250);
            
            return List.of(
                new User(1L, "张三", "zhangsan@example.com"),
                new User(2L, "李四", "lisi@example.com")
            );
        });
    }
    
    private void simulateIOOperation(int delayMillis) {
        try {
            Thread.sleep(delayMillis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    private void simulateIOOperation(String operation, int delayMillis) {
        log.info("IO Operation '{}' on thread: {}", 
            operation, Thread.currentThread());
        simulateIOOperation(delayMillis);
    }
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class User {
        private Long id;
        private String name;
        private String email;
    }
}

5. 数据库操作与虚拟线程

5.1 Repository 层

java

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.concurrent.CompletableFuture;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    /**
     * 异步查询方法
     */
    @Async("virtualThreadExecutor")
    @Query("SELECT u FROM User u WHERE u.name LIKE %:name%")
    CompletableFuture<List<User>> findUsersByNameAsync(String name);
    
    /**
     * 异步保存方法
     */
    @Async("virtualThreadExecutor")
    default CompletableFuture<User> saveUserAsync(User user) {
        return CompletableFuture.completedFuture(save(user));
    }
}

@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private String email;
    private LocalDateTime createdAt;
    
    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
    }
}

5.2 事务处理示例

java

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class TransactionalVirtualThreadService {
    
    private final UserRepository userRepository;
    private final ExecutorService virtualThreadExecutor = 
        Executors.newVirtualThreadPerTaskExecutor();
    
    /**
     * 在虚拟线程中执行事务操作
     * 注意:事务边界管理需要小心
     */
    public CompletableFuture<User> createUserInTransaction(String name, String email) {
        return CompletableFuture.supplyAsync(() -> {
            // 在虚拟线程中执行数据库操作
            User user = new User();
            user.setName(name);
            user.setEmail(email);
            
            log.info("Saving user on virtual thread: {}", Thread.currentThread());
            return userRepository.save(user);
        }, virtualThreadExecutor);
    }
    
    /**
     * 批量插入使用虚拟线程
     */
    public CompletableFuture<List<User>> batchCreateUsers(List<User> users) {
        List<CompletableFuture<User>> futures = users.stream()
            .map(user -> CompletableFuture.supplyAsync(() -> {
                try {
                    // 每个用户插入都在自己的虚拟线程中执行
                    return userRepository.save(user);
                } catch (Exception e) {
                    log.error("Error saving user: {}", user.getName(), e);
                    throw new RuntimeException(e);
                }
            }, virtualThreadExecutor))
            .toList();
        
        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .thenApply(v -> futures.stream()
                .map(CompletableFuture::join)
                .toList());
    }
}

6. 性能测试与监控

6.1 测试 Controller

java

import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

@Slf4j
@RestController
@RequestMapping("/api/performance")
public class PerformanceTestController {
    
    private final ExecutorService virtualThreadExecutor = 
        Executors.newVirtualThreadPerTaskExecutor();
    
    private final ExecutorService platformThreadExecutor = 
        Executors.newFixedThreadPool(100);
    
    private final AtomicInteger virtualThreadCounter = new AtomicInteger(0);
    private final AtomicInteger platformThreadCounter = new AtomicInteger(0);
    
    /**
     * 虚拟线程性能测试
     */
    @PostMapping("/test/virtual-threads")
    public ResponseEntity<TestResult> testVirtualThreads(@RequestParam int requestCount) {
        log.info("Starting virtual threads test with {} requests", requestCount);
        
        Instant start = Instant.now();
        
        // 使用虚拟线程处理并发请求
        List<CompletableFuture<Void>> futures = IntStream.range(0, requestCount)
            .mapToObj(i -> CompletableFuture.runAsync(() -> {
                virtualThreadCounter.incrementAndGet();
                simulateIOOperation(100); // 模拟100ms的IO操作
            }, virtualThreadExecutor))
            .toList();
        
        // 等待所有任务完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        
        Duration duration = Duration.between(start, Instant.now());
        
        TestResult result = new TestResult(
            "virtual-threads",
            requestCount,
            virtualThreadCounter.get(),
            duration.toMillis(),
            duration.toMillis() / (double) requestCount
        );
        
        log.info("Virtual threads test completed: {}", result);
        return ResponseEntity.ok(result);
    }
    
    /**
     * 平台线程性能测试(对比)
     */
    @PostMapping("/test/platform-threads")
    public ResponseEntity<TestResult> testPlatformThreads(@RequestParam int requestCount) {
        log.info("Starting platform threads test with {} requests", requestCount);
        
        Instant start = Instant.now();
        
        List<CompletableFuture<Void>> futures = IntStream.range(0, requestCount)
            .mapToObj(i -> CompletableFuture.runAsync(() -> {
                platformThreadCounter.incrementAndGet();
                simulateIOOperation(100);
            }, platformThreadExecutor))
            .toList();
        
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        
        Duration duration = Duration.between(start, Instant.now());
        
        TestResult result = new TestResult(
            "platform-threads",
            requestCount,
            platformThreadCounter.get(),
            duration.toMillis(),
            duration.toMillis() / (double) requestCount
        );
        
        log.info("Platform threads test completed: {}", result);
        return ResponseEntity.ok(result);
    }
    
    /**
     * 混合负载测试
     */
    @PostMapping("/test/mixed-load")
    public ResponseEntity<Map<String, Object>> testMixedLoad() {
        int ioBoundTasks = 1000;
        int cpuBoundTasks = 100;
        
        Instant start = Instant.now();
        
        // IO密集型任务使用虚拟线程
        List<CompletableFuture<Void>> ioTasks = IntStream.range(0, ioBoundTasks)
            .mapToObj(i -> CompletableFuture.runAsync(() -> {
                simulateIOOperation(50);
            }, virtualThreadExecutor))
            .toList();
        
        // CPU密集型任务使用平台线程池
        List<CompletableFuture<Void>> cpuTasks = IntStream.range(0, cpuBoundTasks)
            .mapToObj(i -> CompletableFuture.runAsync(() -> {
                performCpuIntensiveWork();
            }, platformThreadExecutor))
            .toList();
        
        CompletableFuture.allOf(
            Stream.concat(ioTasks.stream(), cpuTasks.stream())
                .toArray(CompletableFuture[]::new)
        ).join();
        
        Duration duration = Duration.between(start, Instant.now());
        
        Map<String, Object> result = Map.of(
            "total_tasks", ioBoundTasks + cpuBoundTasks,
            "io_tasks", ioBoundTasks,
            "cpu_tasks", cpuBoundTasks,
            "total_time_ms", duration.toMillis(),
            "throughput_tasks_per_second", 
                (ioBoundTasks + cpuBoundTasks) / (duration.toMillis() / 1000.0)
        );
        
        return ResponseEntity.ok(result);
    }
    
    private void simulateIOOperation(int delayMillis) {
        try {
            Thread.sleep(delayMillis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    private void performCpuIntensiveWork() {
        // 模拟CPU密集型计算
        long sum = 0;
        for (int i = 0; i < 1000000; i++) {
            sum += i * i;
        }
    }
    
    @Data
    @AllArgsConstructor
    public static class TestResult {
        private String testType;
        private int totalRequests;
        private int processedRequests;
        private long totalTimeMs;
        private double averageTimePerRequestMs;
    }
}

6.2 监控端点

java

import org.springframework.boot.actuate.endpoint.annotation.*;
import org.springframework.stereotype.Component;

import java.lang.management.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Endpoint(id = "virtualthreads")
public class VirtualThreadsEndpoint {
    
    private final Map<String, Object> metrics = new ConcurrentHashMap<>();
    
    @ReadOperation
    public Map<String, Object> getVirtualThreadMetrics() {
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        
        // 获取所有线程
        long[] threadIds = threadBean.getAllThreadIds();
        int virtualThreadCount = 0;
        int platformThreadCount = 0;
        
        for (long threadId : threadIds) {
            ThreadInfo threadInfo = threadBean.getThreadInfo(threadId);
            if (threadInfo != null) {
                // 检查是否为虚拟线程(通过线程名或其它特征)
                if (threadInfo.getThreadName().contains("VirtualThread")) {
                    virtualThreadCount++;
                } else {
                    platformThreadCount++;
                }
            }
        }
        
        metrics.put("virtual_thread_count", virtualThreadCount);
        metrics.put("platform_thread_count", platformThreadCount);
        metrics.put("total_thread_count", threadBean.getThreadCount());
        metrics.put("peak_thread_count", threadBean.getPeakThreadCount());
        metrics.put("daemon_thread_count", threadBean.getDaemonThreadCount());
        
        // 内存信息
        Runtime runtime = Runtime.getRuntime();
        metrics.put("max_memory_mb", runtime.maxMemory() / 1024 / 1024);
        metrics.put("total_memory_mb", runtime.totalMemory() / 1024 / 1024);
        metrics.put("free_memory_mb", runtime.freeMemory() / 1024 / 1024);
        metrics.put("used_memory_mb", 
            (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024);
        
        return metrics;
    }
}

7. 高级特性与最佳实践

7.1 虚拟线程池配置器

java

import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;

@Configuration
public class AdvancedVirtualThreadConfig {
    
    /**
     * 配置 Tomcat 使用虚拟线程处理请求
     */
    @Bean
    public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
        return protocolHandler -> {
            protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
        };
    }
    
    /**
     * 自定义虚拟线程工厂,添加监控和命名
     */
    @Bean
    public ThreadFactory monitoredVirtualThreadFactory() {
        return Thread.ofVirtual()
            .name("app-virtual-", 0)
            .uncaughtExceptionHandler((t, e) -> {
                // 自定义异常处理
                System.err.println("Uncaught exception in virtual thread: " + t.getName());
                e.printStackTrace();
            })
            .factory();
    }
    
    /**
     * 用于定时任务的虚拟线程调度器
     */
    @Bean
    public ScheduledExecutorService virtualThreadScheduler() {
        return Executors.newScheduledThreadPool(
            0,  // 核心线程数设为0,全部使用虚拟线程
            Thread.ofVirtual().name("scheduled-", 0).factory()
        );
    }
}

7.2 虚拟线程异常处理

java

import org.springframework.web.bind.annotation.*;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

@Slf4j
@RestControllerAdvice
public class VirtualThreadExceptionHandler {
    
    /**
     * 处理虚拟线程中的异常
     */
    @ExceptionHandler(CompletionException.class)
    public ResponseEntity<ErrorResponse> handleCompletionException(
            CompletionException ex) {
        
        Throwable cause = ex.getCause();
        log.error("Virtual thread task failed: {}", cause.getMessage(), cause);
        
        return ResponseEntity.status(500)
            .body(new ErrorResponse("VIRTUAL_THREAD_ERROR", 
                "Task execution failed: " + cause.getMessage()));
    }
    
    /**
     * 处理线程中断异常
     */
    @ExceptionHandler(InterruptedException.class)
    public ResponseEntity<ErrorResponse> handleInterruptedException(
            InterruptedException ex) {
        
        log.warn("Virtual thread was interrupted");
        Thread.currentThread().interrupt(); // 重新设置中断状态
        
        return ResponseEntity.status(503)
            .body(new ErrorResponse("THREAD_INTERRUPTED", 
                "Request processing was interrupted"));
    }
    
    @Data
    @AllArgsConstructor
    public static class ErrorResponse {
        private String code;
        private String message;
    }
}

8. 测试类

java

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.web.client.TestRestTemplate;

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

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class VirtualThreadApplicationTests {
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    void testVirtualThreadHelloEndpoint() {
        var response = restTemplate.getForObject(
            "/api/virtual-threads/hello", 
            String.class
        );
        
        assertThat(response).contains("Hello from virtual thread");
    }
    
    @Test
    void testVirtualThreadPerformance() throws Exception {
        ExecutorService testExecutor = Executors.newVirtualThreadPerTaskExecutor();
        
        long startTime = System.currentTimeMillis();
        
        // 并发执行100个请求
        var futures = java.util.stream.IntStream.range(0, 100)
            .mapToObj(i -> CompletableFuture.runAsync(() -> {
                String response = restTemplate.getForObject(
                    "/api/virtual-threads/hello", 
                    String.class
                );
                assertThat(response).isNotNull();
            }, testExecutor))
            .toArray(CompletableFuture[]::new);
        
        CompletableFuture.allOf(futures).get(10, TimeUnit.SECONDS);
        
        long duration = System.currentTimeMillis() - startTime;
        System.out.printf("100 requests completed in %d ms%n", duration);
        
        testExecutor.shutdown();
    }
}

9. 主启动类

java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class VirtualThreadApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(VirtualThreadApplication.class, args);
        
        // 打印虚拟线程相关信息
        System.out.println("=".repeat(50));
        System.out.println("Virtual Thread Demo Application Started");
        System.out.println("Java Version: " + System.getProperty("java.version"));
        System.out.println("Virtual Threads Enabled: true");
        System.out.println("=".repeat(50));
    }
}

10. 最佳实践总结

10.1 使用场景

  1. IO密集型任务:数据库查询、HTTP请求、文件操作等

  2. 高并发请求处理:Web服务器处理大量并发连接

  3. 异步任务处理:后台任务、批处理作业

  4. 微服务通信:服务间调用、消息处理

10.2 注意事项

  1. 避免 CPU 密集型任务:虚拟线程不适合长时间CPU计算

  2. 线程局部变量:使用 ThreadLocal 要小心,考虑使用 ScopedValue(JDK 21+)

  3. 资源管理:虚拟线程虽然轻量,但大量创建仍需注意资源使用

  4. 调试监控:虚拟线程的堆栈跟踪与传统线程不同

10.3 配置建议

  1. Web 服务器:为 Tomcat/Undertow 配置虚拟线程执行器

  2. 数据库连接池:适当增加连接数以匹配虚拟线程数量

  3. 外部调用:配置合适的超时和重试策略

  4. 监控:使用 Actuator 监控虚拟线程使用情况

这个完整的示例展示了在 Spring Boot 4.0.x + JDK 21 中如何使用虚拟线程,涵盖了从基础配置到高级用法的各个方面。


评论