網易面試:SpringBoot如何開啓虛擬線程?

磊哥課程 2024-06-13 09:19:28

虛擬線程(Virtual Thread)也稱協程或纖程,是一種輕量級的線程實現,與傳統的線程以及操作系統級別的線程(也稱爲平台線程)相比,它的創建開銷更小、資源利用率更高,是 Java 並發編程領域的一項重要創新。

PS:虛擬線程正式發布于 Java 長期支持版(Long Term Suort,LTS)Java 21(也就是 JDK 21)。

虛擬線程是一種在 Java 虛擬機(JVM)層面實現的邏輯線程,不直接和操作系統的物理線程一一對應,因此它可以減少上下文切換所帶來的性能開銷。

操作系統線程、普通線程(Java 線程)和虛擬線程的關系如下:

1.虛擬線程使用

虛擬線程的創建有以下 4 種方式:

Thread.startVirtualThread(Runnable task)Thread.ofVirtual().unstarted(Runnable task)Thread.ofVirtual().factory()Executors.newVirtualThreadPerTaskExecutor()

具體使用如下。

1.1 startVirtualThread

創建虛擬線程,並直接啓動執行任務:

// 創建並啓動虛擬線程Thread.startVirtualThread(() -> { System.out.println("Do virtual thread.");});1.2 unstarted

只創建虛擬線程,但不直接啓動(創建之後通過 start 啓動):

// 創建虛擬線程Thread vt = Thread.ofVirtual().unstarted(()->{ System.out.println("Do virtual thread.");});// 運行虛擬線程vt.start();1.3 factory

先創建虛擬線程工廠,然後再使用工廠創建虛擬線程,之後再調用 start() 方法進行執行:

// 創建虛擬線程工廠ThreadFactory tf = Thread.ofVirtual().factory();// 創建虛擬線程Thread vt = tf.newThread(()->{ System.out.println("Do virtual thread.");});// 運行虛擬線程vt.start();1.4 newVirtualThreadPerTaskExecutor

創建虛擬線程池:

// 創建一個支持虛擬線程的線程池ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();executor.submit(()->{ System.out.println("Do virtual thread.");});2.虛擬線程 VS 普通線程

虛擬線程和普通線程的區別主要體現在以下幾點:

普通線程是和操作系統的物理線程是一一對應的,而虛擬線程是 JVM 層面的邏輯線程,並不和操作系統的物理線程一一對應,它可以看作是輕量級的線程。普通線程默認創建的是用戶線程(而守護線程),而虛擬線程是守護線程,並且其守護線程的屬性不能被修改,如果修改就會報錯,如下圖所示:

虛擬線程由 JVM 調度和使用,避免了普通線程頻繁切換的性能開銷,所以相比于普通的線程來說,運行效率更高。3.SpringBoot開啓虛擬線程

以最新版的 Spring Boot 3.x 爲例,我們開啓虛擬線程很簡單,只需要在 Spring Boot 配置文件中設置“spring.threads.virtual.enabled”爲“true”即可開啓,以 application.yml 爲例,啓用虛擬線程配置如下:

spring: threads: virtual: enabled: true # 啓用虛擬線程

這樣 Spinrg Boot 在啓動 Tomcat 容器時,會使用一個虛擬線程執行器來代表原有的平台線程池。

PS:這裏是虛擬線程執行器,不是虛擬線程池。

如果以上配置未生效的話,還可以通過修改 Tomcat 配置類,讓其使用虛擬線程來處理每一個請求,配置代碼如下:

import java.util.concurrent.Executors;import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic TomcatConfiguration { @Bean public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() { return protocolHandler -> { // 使用虛擬線程來處理每一個請求 protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); }; }}4.異步任務開啓虛擬線程

如果你想爲 Spring Boot 中的異步任務 @Async 也配置虛擬線程的話,可以在 AsyncConfigurer 配置類中設置,配置代碼如下:

import java.util.concurrent.Executor;import java.util.concurrent.Executors;import org.springframework.context.annotation.Configuration;import org.springframework.core.task.support.TaskExecutorAdapter;import org.springframework.scheduling.annotation.AsyncConfigurer;import org.springframework.scheduling.annotation.EnableAsync;@Configuration@EnableAsync // 開啓異步任務public AsyncTaskConfiguration implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new TaskExecutorAdapter(Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name("virtual-async#", 1).factory())); }}課後思考

說說虛擬線程的底層實現?有了虛擬線程後還需要虛擬線程池嗎?爲什麽?

本文已收錄到我的面試小站 [www.javacn.site](https://www.javacn.site),其中包含的內容有:Redis、JVM、並發、並發、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、設計模式、消息隊列等模塊。

0 阅读:35

磊哥課程

簡介:感謝大家的關注