最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

虛擬線程在Spring?Boot中的正確使用方式及最佳實(shí)踐

 更新時(shí)間:2026年03月18日 08:34:43   作者:往事隨風(fēng)去  
虛擬線程是Java19引入的一項(xiàng)新特性,它屬于Project Loom項(xiàng)目的一部分,與傳統(tǒng)的線程不同,虛擬線程并不是由操作系統(tǒng)直接管理,而是由Java虛擬機(jī)控制,這篇文章主要介紹了虛擬線程在Spring?Boot中的正確使用方式及最佳實(shí)踐的相關(guān)資料,需要的朋友可以參考下

一、概述

Java 21引入了虛擬線程(Virtual Threads),這是Project Loom的核心特性。虛擬線程是輕量級(jí)線程,可以顯著提高應(yīng)用程序的并發(fā)處理能力,特別適合I/O密集型任務(wù)。

在Spring Boot 3.2+中,已經(jīng)內(nèi)置了對(duì)虛擬線程的支持,可以通過簡單的配置啟用。

二、Spring Boot 3.2+ 虛擬線程自動(dòng)配置

1. 啟用虛擬線程(已在項(xiàng)目中配置)

application.yml 中已經(jīng)配置:

spring:
  threads:
    virtual:
      enabled: true

這個(gè)配置會(huì)自動(dòng):

  • @Async 方法啟用虛擬線程執(zhí)行器
  • 為 Spring MVC 的請(qǐng)求處理啟用虛擬線程
  • 為 Spring WebFlux 啟用虛擬線程

2. 驗(yàn)證虛擬線程是否啟用

可以通過以下方式驗(yàn)證:

@SpringBootTest
public class VirtualThreadTest {
    
    @Test
    public void testVirtualThread() {
        Thread thread = Thread.ofVirtual().start(() -> {
            System.out.println("虛擬線程名稱: " + Thread.currentThread().getName());
            System.out.println("是否為虛擬線程: " + Thread.currentThread().isVirtual());
        });
        try {
            thread.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

三、使用方式

方式一:Spring Boot自動(dòng)配置(推薦)

1.1 異步方法中使用虛擬線程

配置類改造(推薦):

/**
 * 異步線程池配置(虛擬線程版本)
 * 當(dāng) spring.threads.virtual.enabled=true 時(shí)使用虛擬線程
 *
 * @author
 * @date 2024-10-31
 */
@Slf4j
@Configuration
@EnableAsync
public class VirtualThreadAsyncConfig implements AsyncConfigurer {

    /**
     * 虛擬線程異步執(zhí)行器
     * Spring Boot 3.2+ 會(huì)自動(dòng)創(chuàng)建虛擬線程執(zhí)行器,這里提供手動(dòng)配置示例
     */
    @Bean(name = "virtualThreadExecutor")
    @ConditionalOnProperty(name = "spring.threads.virtual.enabled", havingValue = "true", matchIfMissing = false)
    public Executor virtualThreadExecutor() {
        return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
    }

    /**
     * 默認(rèn)異步執(zhí)行器
     * 如果啟用虛擬線程,Spring Boot會(huì)自動(dòng)使用虛擬線程執(zhí)行器
     */
    @Override
    public Executor getAsyncExecutor() {
        // Spring Boot 3.2+ 會(huì)自動(dòng)使用虛擬線程執(zhí)行器(如果啟用)
        // 如果需要手動(dòng)指定,可以返回 virtualThreadExecutor()
        return Executors.newVirtualThreadPerTaskExecutor();
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

使用示例:

@Service
@Slf4j
public class ExampleService {

    /**
     * 使用默認(rèn)虛擬線程執(zhí)行器
     */
    @Async
    public CompletableFuture<String> asyncMethod1() {
        log.info("當(dāng)前線程: {}, 是否為虛擬線程: {}", 
            Thread.currentThread().getName(), 
            Thread.currentThread().isVirtual());
        // 執(zhí)行異步任務(wù)
        return CompletableFuture.completedFuture("完成");
    }

    /**
     * 指定使用虛擬線程執(zhí)行器
     */
    @Async("virtualThreadExecutor")
    public CompletableFuture<String> asyncMethod2() {
        log.info("當(dāng)前線程: {}, 是否為虛擬線程: {}", 
            Thread.currentThread().getName(), 
            Thread.currentThread().isVirtual());
        return CompletableFuture.completedFuture("完成");
    }
}

1.2 Web請(qǐng)求處理中使用虛擬線程

Spring Boot 3.2+ 啟用虛擬線程后,所有Web請(qǐng)求會(huì)自動(dòng)使用虛擬線程處理,無需額外配置。

驗(yàn)證方式:

@RestController
@RequestMapping("/api/test")
@Slf4j
public class VirtualThreadTestController {

    @GetMapping("/virtual-thread")
    public Map<String, Object> testVirtualThread() {
        Thread currentThread = Thread.currentThread();
        Map<String, Object> result = new HashMap<>();
        result.put("threadName", currentThread.getName());
        result.put("isVirtual", currentThread.isVirtual());
        result.put("threadId", currentThread.threadId());
        log.info("請(qǐng)求處理線程: {}, 是否為虛擬線程: {}", 
            currentThread.getName(), currentThread.isVirtual());
        return result;
    }
}

1.3 定時(shí)任務(wù)中使用虛擬線程

配置類改造:

/**
 * 定時(shí)任務(wù)配置(虛擬線程版本)
 *
 * @author 
 * @date 2024-10-31
 */
@Slf4j
@Configuration
@EnableScheduling
@ConditionalOnProperty(name = "spring.threads.virtual.enabled", havingValue = "true")
public class VirtualThreadSchedulingConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskScheduler());
    }

    @Bean
    public Executor taskScheduler() {
        return Executors.newVirtualThreadPerTaskExecutor();
    }
}

使用示例:

@Component
@Slf4j
public class ScheduledTaskExample {

    /**
     * 定時(shí)任務(wù)會(huì)自動(dòng)使用虛擬線程執(zhí)行器
     */
    @Scheduled(fixedRate = 5000)
    public void scheduledTask() {
        log.info("定時(shí)任務(wù)執(zhí)行 - 線程: {}, 是否為虛擬線程: {}", 
            Thread.currentThread().getName(), 
            Thread.currentThread().isVirtual());
    }
}

方式二:手動(dòng)創(chuàng)建虛擬線程執(zhí)行器

2.1 改進(jìn)現(xiàn)有的VirtualThreadUtils工具類

/**
 * 虛擬線程工具類(改進(jìn)版)
 *
 * @author
 * @date 2024-10-31
 */
@Slf4j
@Component
public class VirtualThreadUtils {

    private static final ExecutorService EXECUTOR = Executors.newVirtualThreadPerTaskExecutor();

    /**
     * 執(zhí)行虛擬線程任務(wù)
     *
     * @param task 任務(wù)
     * @return Future
     */
    public static Future<?> exeVirtualThread(Runnable task) {
        return EXECUTOR.submit(() -> {
            try {
                log.debug("虛擬線程執(zhí)行任務(wù) - 線程: {}, 是否為虛擬線程: {}", 
                    Thread.currentThread().getName(), 
                    Thread.currentThread().isVirtual());
                task.run();
            } catch (Exception e) {
                log.error("虛擬線程執(zhí)行任務(wù)異常", e);
                throw e;
            }
        });
    }

    /**
     * 執(zhí)行虛擬線程任務(wù)(帶返回值)
     *
     * @param task 任務(wù)
     * @param <T>  返回值類型
     * @return Future
     */
    public static <T> Future<T> exeVirtualThread(java.util.concurrent.Callable<T> task) {
        return EXECUTOR.submit(() -> {
            try {
                log.debug("虛擬線程執(zhí)行任務(wù) - 線程: {}, 是否為虛擬線程: {}", 
                    Thread.currentThread().getName(), 
                    Thread.currentThread().isVirtual());
                return task.call();
            } catch (Exception e) {
                log.error("虛擬線程執(zhí)行任務(wù)異常", e);
                throw e;
            }
        });
    }

    @PreDestroy
    public void destroy() {
        log.info("關(guān)閉虛擬線程執(zhí)行器");
        EXECUTOR.shutdown();
        try {
            if (!EXECUTOR.awaitTermination(60, TimeUnit.SECONDS)) {
                EXECUTOR.shutdownNow();
                if (!EXECUTOR.awaitTermination(60, TimeUnit.SECONDS)) {
                    log.error("虛擬線程執(zhí)行器未能正常關(guān)閉");
                }
            }
        } catch (InterruptedException e) {
            EXECUTOR.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

2.2 在CompletableFuture中使用虛擬線程

@Service
@Slf4j
public class CompletableFutureExample {

    /**
     * 使用虛擬線程執(zhí)行器執(zhí)行CompletableFuture
     */
    public CompletableFuture<List<String>> processDataAsync() {
        Executor virtualExecutor = Executors.newVirtualThreadPerTaskExecutor();
        
        CompletableFuture<List<String>> future = CompletableFuture
            .supplyAsync(() -> {
                log.info("異步任務(wù)執(zhí)行 - 線程: {}, 是否為虛擬線程: {}", 
                    Thread.currentThread().getName(), 
                    Thread.currentThread().isVirtual());
                return fetchData();
            }, virtualExecutor)
            .thenApplyAsync(data -> {
                log.info("處理數(shù)據(jù) - 線程: {}, 是否為虛擬線程: {}", 
                    Thread.currentThread().getName(), 
                    Thread.currentThread().isVirtual());
                return processData(data);
            }, virtualExecutor);
        
        return future;
    }

    private List<String> fetchData() {
        // 模擬I/O操作
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return Arrays.asList("data1", "data2", "data3");
    }

    private List<String> processData(List<String> data) {
        return data.stream()
            .map(String::toUpperCase)
            .collect(Collectors.toList());
    }
}

方式三:為特定場(chǎng)景配置虛擬線程執(zhí)行器

3.1 消息隊(duì)列處理使用虛擬線程

/**
 * RabbitMQ虛擬線程配置
 *
 * @author 往事隨風(fēng)去
 * @date 2024-10-31
 */
@Slf4j
@Configuration
@ConditionalOnProperty(name = "spring.threads.virtual.enabled", havingValue = "true")
public class RabbitMQVirtualThreadConfig {

    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
            ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        // 使用虛擬線程執(zhí)行器處理消息
        factory.setTaskExecutor(new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor()));
        return factory;
    }
}

3.2 數(shù)據(jù)庫操作使用虛擬線程

對(duì)于MyBatis等數(shù)據(jù)庫操作,通常不需要特別配置,因?yàn)椋?/p>

  1. 數(shù)據(jù)庫連接池(如Druid)會(huì)管理連接
  2. 虛擬線程在執(zhí)行I/O阻塞操作時(shí)會(huì)自動(dòng)釋放平臺(tái)線程
  3. 可以提高并發(fā)查詢能力

四、最佳實(shí)踐

1. 適用場(chǎng)景

虛擬線程適合:

  • I/O密集型任務(wù)(數(shù)據(jù)庫查詢、HTTP請(qǐng)求、文件操作)
  • 大量并發(fā)請(qǐng)求處理
  • 異步任務(wù)處理
  • Web請(qǐng)求處理

虛擬線程不適合:

  • CPU密集型任務(wù)(計(jì)算密集型,應(yīng)使用平臺(tái)線程池)
  • 需要線程本地存儲(chǔ)(ThreadLocal)的場(chǎng)景(虛擬線程會(huì)頻繁切換)
  • 需要精確控制線程數(shù)量的場(chǎng)景

2. 注意事項(xiàng)

2.1 線程本地存儲(chǔ)(ThreadLocal)

虛擬線程會(huì)頻繁切換,ThreadLocal的使用需要注意:

// ? 不推薦:在虛擬線程中使用ThreadLocal存儲(chǔ)大量數(shù)據(jù)
ThreadLocal<List<String>> threadLocal = new ThreadLocal<>();

// ? 推薦:使用ScopedValue(Java 21+)或謹(jǐn)慎使用ThreadLocal
ScopedValue<String> scopedValue = ScopedValue.newInstance();

2.2 線程池大小配置

啟用虛擬線程后,不需要配置線程池大小,虛擬線程會(huì)自動(dòng)管理:

# ? 不需要配置這些(虛擬線程會(huì)自動(dòng)管理)
server:
  tomcat:
    threads:
      max: 400  # 虛擬線程模式下無效
      min-spare: 100  # 虛擬線程模式下無效

2.3 監(jiān)控和調(diào)試

虛擬線程的監(jiān)控需要使用新的API:

@Service
@Slf4j
public class VirtualThreadMonitor {

    @Scheduled(fixedRate = 60000)
    public void monitorVirtualThreads() {
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        long[] threadIds = threadBean.getAllThreadIds();
        
        long virtualThreadCount = Arrays.stream(threadIds)
            .mapToObj(id -> {
                ThreadInfo info = threadBean.getThreadInfo(id);
                return info != null ? Thread.ofPlatform().getThreadGroup()
                    .findThread(id) : null;
            })
            .filter(Objects::nonNull)
            .filter(Thread::isVirtual)
            .count();
        
        log.info("虛擬線程數(shù)量: {}", virtualThreadCount);
    }
}

3. 性能優(yōu)化建議

3.1 混合使用平臺(tái)線程和虛擬線程

@Configuration
public class HybridThreadConfig {

    /**
     * CPU密集型任務(wù)使用平臺(tái)線程池
     */
    @Bean("cpuIntensiveExecutor")
    public Executor cpuIntensiveExecutor() {
        int processors = Runtime.getRuntime().availableProcessors();
        return Executors.newFixedThreadPool(processors);
    }

    /**
     * I/O密集型任務(wù)使用虛擬線程
     */
    @Bean("ioIntensiveExecutor")
    public Executor ioIntensiveExecutor() {
        return Executors.newVirtualThreadPerTaskExecutor();
    }
}

3.2 避免在虛擬線程中執(zhí)行長時(shí)間CPU計(jì)算

@Service
public class TaskService {

    @Autowired
    @Qualifier("cpuIntensiveExecutor")
    private Executor cpuExecutor;

    @Autowired
    @Qualifier("ioIntensiveExecutor")
    private Executor ioExecutor;

    public void processTask() {
        // I/O操作使用虛擬線程
        CompletableFuture<String> data = CompletableFuture
            .supplyAsync(this::fetchData, ioExecutor);
        
        // CPU計(jì)算使用平臺(tái)線程
        CompletableFuture<String> result = data
            .thenApplyAsync(this::heavyComputation, cpuExecutor);
    }
}

五、遷移建議

1. 逐步遷移

  1. 第一步:啟用虛擬線程

    spring:
      threads:
        virtual:
          enabled: true
    
  2. 第二步:改造異步配置

    • 將線程池配置類改造為使用虛擬線程
    • ScheduledTaskCofiguration 改造為使用虛擬線程
  3. 第三步:測(cè)試和驗(yàn)證

    • 驗(yàn)證Web請(qǐng)求是否使用虛擬線程
    • 驗(yàn)證異步方法是否使用虛擬線程
    • 驗(yàn)證定時(shí)任務(wù)是否使用虛擬線程
  4. 第四步:性能測(cè)試

    • 對(duì)比啟用虛擬線程前后的性能
    • 監(jiān)控內(nèi)存使用情況
    • 監(jiān)控線程數(shù)量

2. 回滾方案

如果出現(xiàn)問題,可以快速回滾:

spring:
  threads:
    virtual:
      enabled: false  # 禁用虛擬線程,恢復(fù)傳統(tǒng)線程池

六、總結(jié)

虛擬線程在Spring Boot中的正確使用方式:

  1. 啟用方式:配置 spring.threads.virtual.enabled=true
  2. Web請(qǐng)求:自動(dòng)使用虛擬線程處理(無需額外配置)
  3. 異步方法:通過 @Async 自動(dòng)使用虛擬線程
  4. 定時(shí)任務(wù):需要配置 SchedulingConfigurer
  5. 手動(dòng)創(chuàng)建:使用 Executors.newVirtualThreadPerTaskExecutor()
  6. 注意事項(xiàng):避免CPU密集型任務(wù),謹(jǐn)慎使用ThreadLocal

通過合理使用虛擬線程,可以顯著提高I/O密集型應(yīng)用的并發(fā)處理能力,減少線程資源消耗。

到此這篇關(guān)于虛擬線程在Spring Boot中的正確使用方式及最佳實(shí)踐的文章就介紹到這了,更多相關(guān)SpringBoot中虛擬線程使用方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

海宁市| 壤塘县| 常德市| 平潭县| 大宁县| 苏尼特右旗| 泸水县| 汕尾市| 隆子县| 资溪县| 葫芦岛市| 郁南县| 历史| 开江县| 射洪县| 辽宁省| 东阳市| 林芝县| 汉寿县| 林芝县| 吴旗县| 葫芦岛市| 海安县| 竹北市| 沧州市| 仲巴县| 张掖市| 广水市| 永靖县| 开江县| 唐海县| 阳谷县| 诸城市| 黑龙江省| 罗甸县| 繁昌县| 建昌县| 大竹县| 集安市| 安陆市| 三江|