亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot3中使用虛擬線程的詳細(xì)過程

 更新時間:2025年06月06日 11:13:28   作者:颯颯的宇y  
虛擬線程主要解決的問題是減少I/O密集型任務(wù)的I/O阻塞,這篇文章主要介紹了SpringBoot3中使用虛擬線程的詳細(xì)過程,需要的朋友可以參考下

Java21、SpringBoot3中使用虛擬線程

引言

最近有讀取文件中數(shù)據(jù)的需求,且數(shù)據(jù)量百萬至千萬,普通的多線程讀取方式還是很慢。遂想到Java21虛擬線程,在網(wǎng)上學(xué)習(xí)了一圈,簡單的在這里記一個筆記,方便日后查找。

以下內(nèi)容是個人理解,注解辨別。

一、什么是虛擬線程,有什么用

1、虛擬線程是Java19提出來的一個概念,Java19提供特性預(yù)覽,開放實裝是Java21(2023年9月),目前來說(2024年3月),還是一個比較新的特性,對于一些不是很常見的庫可能尚未適配。

2、虛擬線程主要解決的問題是減少I/O密集型任務(wù)I/O阻塞。傳統(tǒng)的多線程在處理I/O的時候,例如某個線程在處理某個任務(wù),如果遇到I/O例如網(wǎng)絡(luò)通信、文件讀取,受限于網(wǎng)絡(luò)速度機器的硬盤I/O速度等,這個線程會阻塞等待I/O的完成,然后再繼續(xù)往下執(zhí)行任務(wù)。這就帶來了一個問題,由于存在I/O過程,這個線程它不干活了,就在那里阻塞干等I/O完成,偷懶了一會兒,導(dǎo)致了CPU的利用率其實沒有達(dá)到理想狀態(tài)。

3、而虛擬線程則是在線程遇到I/O阻塞時,會放暫時放棄等待去做其他事,等I/O完成它才會回來繼續(xù)執(zhí)行任務(wù),無疑這種方式提高了CPU的利用率,讓它無法再偷懶。
虛擬線程是由JVM來管理的,不由系統(tǒng)管理,并且它十分輕量,虛擬線程之間的切換開銷十分的小,所以你甚至可以開啟上百萬個虛擬線程。

4、虛擬線程并沒有增加實際的CPU可用線程,而是增加了線程的利用率,所以在面對CPU密集型任務(wù)時,如數(shù)學(xué)計算等,它與傳統(tǒng)的線程沒有區(qū)別,因為CPU密集型任務(wù)不存在大量的I/O等待。
如果你的需求中存在大量I/O等待導(dǎo)致性能瓶頸,那么可以考慮使用虛擬線程。

二、JavaSE中使用虛擬線程

官方對虛擬線程做了很多封裝,你可以很簡單的使用它

Thread.ofVirtual().start(() -> {
	//異步任務(wù),這里的參數(shù)不用lambda表達(dá)式的話要傳一個實現(xiàn)Runnable的類
}); //開啟一個虛擬線程

部分源代碼:

public static Builder.OfVirtual ofVirtual() {
        return new ThreadBuilders.VirtualThreadBuilder();
}
public Thread start(Runnable task) {
            Thread thread = unstarted(task);
            thread.start();
            return thread;
}

同時,官方還提供了使用平臺線程(真實線程)的方法:

Thread.ofPlatform().start(() -> {
	//異步任務(wù),這里的參數(shù)不用lambda表達(dá)式的話要傳一個實現(xiàn)Runnable的類
}); //開啟一個平臺線程

當(dāng)然,在實際使用中,我們不可能只使用一個虛擬線程,所以官方提供了一個類似于線程池的方法:

var executors = Executors.newVirtualThreadPerTaskExecutor() //開啟一個“虛擬線程池”
executors.submit(() -> {
	//異步任務(wù),這里的參數(shù)不用lambda表達(dá)式的話要傳一個實現(xiàn)Runnable的類
}); //向“虛擬線程池”中提交一個任務(wù)

說明一下:
首先var關(guān)鍵字是Java10引入的,類似于C++中的auto,它可以自動類型推斷,就是說我們以后可以不用寫類似 ArrayList<String> list = new ArrayList<>(); 這樣的代碼了,直接 var list = new ArrayList<String>(); 編譯器會自己類型推斷,但是這么寫你得注意變量名,不然讀起來會很麻煩。還有var關(guān)鍵字只能用于局部變量,成員變量、形參等都不行。

這種方式用虛擬線程,JVM會自動利用機器可用的真實線程來跑這些虛擬線程,不用額外配置

使用“虛擬線程池”的時候最好搭配try-with-resource,以達(dá)到資源的自動釋放:

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
	for (int i = 0; i < 1000000; i++) {
	    int finalI = i;
	    var future = executor.submit(() -> {
	        System.out.println("任務(wù) " + finalI +" 運行在 " + Thread.currentThread());
	        TimeUnit.SECONDS.sleep(3);//模擬阻塞
	        // 執(zhí)行其他操作
	        return "ok";
	    });
	}
}

你可以在下方使用 Future.get() 的方式來等待線程執(zhí)行完畢

以上代碼執(zhí)行結(jié)果:

...
任務(wù) 992 運行在 VirtualThread[#1038]/runnable@ForkJoinPool-1-worker-12
任務(wù) 578 運行在 VirtualThread[#622]/runnable@ForkJoinPool-1-worker-6
任務(wù) 802 運行在 VirtualThread[#848]/runnable@ForkJoinPool-1-worker-4
任務(wù) 997 運行在 VirtualThread[#1043]/runnable@ForkJoinPool-1-worker-13
...

我們可以看到線程名成為了 VirtualThread ,它們運行在不同的真實線程上 worker-13 、 worker-4

三、SpringBoot中使用虛擬線程

在SpringBoot中使用虛擬線程要求SpringBoot的版本最低是 3.x ,JDK的版本不能低于21

*** 注意,暫時不要用Undertow作為Servlet容器來使用虛擬線程,可能會有內(nèi)存溢出等問題,你的內(nèi)存占用會飆得老高,SpringBoot官方目前說的是Undertow的問題,另外還補充說如果這個問題沒能得到解決的話,未來可能移除對Undertow的虛擬線程支持,所以暫時別在生產(chǎn)環(huán)境中使用。官方GitHub issues 原文地址

1、使用

使用Jdk21,Maven引入SpringBoot3.x

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.2.1</version>
</dependency>

新建一個配置類,添加兩個Bean:

@Configuration
public class Config {
    @Bean
    public AsyncTaskExecutor asyncTaskExecutor(){
        return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
    }
    @Bean
    public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
        return protocolHandler -> protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
    }
}

說明一下,第一個Bean AsyncTaskExecutor 是為了讓SpringBoot在你使用 @Async 注解的時候用虛擬線程執(zhí)行你的 @Async 任務(wù)。

第二個Bean TomcatProtocolHandlerCustomizer 是為了讓Tomcat用虛擬線程來接請求的。我們可以測試一下,寫一個Controller和一個Service:

@RestController
@RequestMapping("/base")
public class TestController {
    @Resource
    private TestService service;
    @GetMapping("/test")
    public String test(){
        System.out.println("---> " + Thread.currentThread());
        service.test();
        return "ok";
    }
}
@EnableAsync
@Service
public class TestService {
    @Async
    public void test(){
        System.out.println("================> " + Thread.currentThread());
    }
}

運行這個服務(wù),訪問 localhost:8080/base/test 接口的時候,會打?。?/p>

---> VirtualThread[#65]/runnable@ForkJoinPool-1-worker-1
================> VirtualThread[#71]/runnable@ForkJoinPool-1-worker-4

發(fā)現(xiàn)都是虛擬線程,我們?nèi)偛判陆ǖ呐渲妙愔凶⑨尩粝旅娴?TomcatProtocolHandlerCustomizer 這個Bean,重啟服務(wù)再訪問接口:

---> Thread[#61,http-nio-8080-exec-1,5,main]
================> VirtualThread[#78]/runnable@ForkJoinPool-1-worker-1

會發(fā)現(xiàn)接收請求的線程不是虛擬線程了,同樣的,注釋掉上面的 AsyncTaskExecutor 那么我們用 @Async 注解的方法也是不使用虛擬線程了。

如果你想提高請求處理量的話,就注入下面這個Bean,只是想使用虛擬線程做其他事的話,下面這個Bean是可選的。

2、線程池問題

如果你的打印內(nèi)容出現(xiàn):

.s.a.AnnotationAsyncExecutionInterceptor : More than one TaskExecutor bean found within the context,
 and none is named 'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly as an alias) 
 in order to use it for async processing: [asyncTaskExecutor, taskScheduler]

或者你打印的線程信息類似:

Thread[#129,SimpleAsyncTaskExecutor-2,5,VirtualThreads]

第一個警告的意思是在上下文中找到多個TaskExecutor bean,但沒有一個名稱為“TaskExecutor”。將其中一個標(biāo)記為主任務(wù)或?qū)⑵涿麨?ldquo;taskExecutor”(可能是別名),以便將其用于異步處理:[asyncTaskExecutor,taskScheduler]
問題是項目中引入的線程池過多,Spring容器不知道用哪一個,我們只需要在AsyncTaskExecutor這個Bean上添加一個@Primary將我們設(shè)置的線程池設(shè)置為主線程池就行了:

@Bean
@Primary // 將我們設(shè)置的虛擬線程池作為主線程池
public AsyncTaskExecutor asyncTaskExecutor(){
	return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
}

四、總結(jié)

目前我沒有做具體的性能測試,有興趣的可以做做壓測。后續(xù)我做了測試的話會更新這篇博客。
虛擬線程目前來說是一個很新的特性,可能會有很多問題尚未發(fā)現(xiàn),使用要謹(jǐn)慎。
此外,CPU密集型任務(wù)目前來說就不建議用虛擬線程了,性能沒提升。

參考文獻(xiàn)

1、簡單記錄下 Spring Boot 使用虛擬線程Virtual Threads(Java的協(xié)程)的方法
2、Java21手冊(一):虛擬線程 Virtual Threads

到此這篇關(guān)于SpringBoot3中使用虛擬線程的文章就介紹到這了,更多相關(guān)SpringBoot使用虛擬線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring中的循環(huán)依賴問題

    Spring中的循環(huán)依賴問題

    在Spring框架中,循環(huán)依賴是指兩個或多個Bean相互依賴,這導(dǎo)致在Bean的創(chuàng)建過程中出現(xiàn)依賴死鎖,為了解決這一問題,Spring引入了三級緩存機制,包括singletonObjects、earlySingletonObjects和singletonFactories
    2024-09-09
  • Java中的內(nèi)存模型JMM詳細(xì)解讀

    Java中的內(nèi)存模型JMM詳細(xì)解讀

    這篇文章主要介紹了Java中的內(nèi)存模型JMM詳細(xì)解讀,Java?對內(nèi)存的抽象模型如下,每個線程都有一塊自己的私有內(nèi)存(也稱為工作內(nèi)存),當(dāng)線程使用變量時,會把主內(nèi)存里面的變量復(fù)制到工作內(nèi)存,線程讀寫變量時操作的是自己工作內(nèi)存中的變量,需要的朋友可以參考下
    2023-12-12
  • Java多線程中的wait、notify和park、unpark的使用詳解

    Java多線程中的wait、notify和park、unpark的使用詳解

    這篇文章主要介紹了Java多線程中的wait、notify和park、unpark的使用詳解,它們都是線程之間進(jìn)行協(xié)作的手段,都屬于 Object 對象的方法,必須獲得此對象的鎖,才能調(diào)用這幾個方法,需要的朋友可以參考下
    2023-12-12
  • 淺析Java和Scala中的Future

    淺析Java和Scala中的Future

    這篇文章主要介紹了Java和Scala中的Future的相關(guān)資料,需要的朋友可以參考下
    2017-10-10
  • Intellij idea 代碼提示忽略字母大小寫和常用快捷鍵及設(shè)置步驟

    Intellij idea 代碼提示忽略字母大小寫和常用快捷鍵及設(shè)置步驟

    這篇文章主要介紹了Intellij idea 代碼提示忽略字母大小寫和常用快捷鍵及設(shè)置步驟,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-02-02
  • 分析Java非阻塞算法Lock-Free的實現(xiàn)

    分析Java非阻塞算法Lock-Free的實現(xiàn)

    非阻塞算法一般會使用CAS來協(xié)調(diào)線程的操作。雖然非阻塞算法有諸多優(yōu)點,但是在實現(xiàn)上要比基于鎖的算法更加繁瑣和負(fù)責(zé)。本文將會介紹兩個是用非阻塞算法實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)。
    2021-06-06
  • 關(guān)于@Scheduled參數(shù)及cron表達(dá)式解釋

    關(guān)于@Scheduled參數(shù)及cron表達(dá)式解釋

    這篇文章主要介紹了關(guān)于@Scheduled參數(shù)及cron表達(dá)式解釋,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Flyway詳解及Springboot集成Flyway的詳細(xì)教程

    Flyway詳解及Springboot集成Flyway的詳細(xì)教程

    Flayway是一款數(shù)據(jù)庫版本控制管理工具,,支持?jǐn)?shù)據(jù)庫版本自動升級,Migrations可以寫成sql腳本,也可以寫在java代碼里。這篇文章主要介紹了Flyway詳解及Springboot集成Flyway的詳細(xì)教程的相關(guān)資料,需要的朋友可以參考下
    2020-07-07
  • Maven項目中resources配置總結(jié)

    Maven項目中resources配置總結(jié)

    這篇文章主要介紹了Maven項目中resources配置總結(jié),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • PowerJob的DesignateServer工作流程源碼解讀

    PowerJob的DesignateServer工作流程源碼解讀

    這篇文章主要介紹了PowerJob的DesignateServer工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01

最新評論