Spring?Boot3虛擬線程的使用步驟詳解
在Spring Boot非Web應(yīng)用中,使用虛擬線程時(shí)程序提前終止的問題及解決方案,可以通過以下步驟深入理解和驗(yàn)證:
問題根源分析
JVM退出機(jī)制Java中,當(dāng)所有非守護(hù)線程結(jié)束時(shí),JVM會(huì)立即退出。即使存在正在運(yùn)行的守護(hù)線程(如虛擬線程),JVM也不會(huì)等待它們完成。
虛擬線程的特性
- 虛擬線程(
Thread.ofVirtual())默認(rèn)是守護(hù)線程,且無法通過setDaemon(false)修改。 - 虛擬線程由JVM管理,不直接映射到操作系統(tǒng)線程,因此其生命周期與JVM的退出策略緊密相關(guān)。
- 虛擬線程(
非Web應(yīng)用的默認(rèn)行為非Web應(yīng)用啟動(dòng)后,若沒有其他非守護(hù)線程(如主線程、定時(shí)任務(wù)線程),JVM會(huì)立即退出。即使啟用了虛擬線程執(zhí)行任務(wù),由于虛擬線程是守護(hù)線程,無法阻止JVM退出。
解決方案驗(yàn)證
Spring Boot從3.2.0-RC1開始提供spring.main.keep-alive=true配置,其原理如下:
KeepAlive監(jiān)聽器啟用后,Spring Boot會(huì)注冊(cè)一個(gè)
KeepAlive監(jiān)聽器,在上下文刷新完成后啟動(dòng)一個(gè)非守護(hù)線程(命名為keep-alive),該線程無限期休眠(Thread.sleep(Long.MAX_VALUE)),確保JVM不會(huì)退出。線程終止邏輯當(dāng)Spring上下文關(guān)閉時(shí)(如調(diào)用
SpringApplication.exit()),KeepAlive監(jiān)聽器會(huì)中斷keep-alive線程,允許JVM正常退出。
驗(yàn)證實(shí)驗(yàn)
實(shí)驗(yàn)1:未啟用keep-alive
// 虛擬線程執(zhí)行任務(wù)
OfVirtual virtual = Thread.ofVirtual().name("Task-");
virtual.start(() -> {
System.out.println("任務(wù)開始");
try { TimeUnit.SECONDS.sleep(5); }
catch (InterruptedException e) {}
System.out.println("任務(wù)結(jié)束");
});
// 主線程休眠1秒
TimeUnit.SECONDS.sleep(1);
結(jié)果:僅輸出任務(wù)開始,程序立即退出。
原因:虛擬線程是守護(hù)線程,主線程結(jié)束后JVM直接退出。
實(shí)驗(yàn)2:?jiǎn)⒂胟eep-alive
在application.properties中添加:
spring.main.keep-alive=true
結(jié)果:程序持續(xù)運(yùn)行5秒,完整輸出任務(wù)開始和任務(wù)結(jié)束。
原因:keep-alive線程阻止JVM退出,等待虛擬線程任務(wù)完成。
擴(kuò)展建議
任務(wù)完成檢測(cè)如果任務(wù)需要顯式通知完成,可結(jié)合
CountDownLatch或CompletableFuture:CountDownLatch latch = new CountDownLatch(1); OfVirtual virtual = Thread.ofVirtual().name("Task-"); virtual.start(() -> { try { /* 執(zhí)行任務(wù) */ } finally { latch.countDown(); } }); latch.await(); // 阻塞直到任務(wù)完成資源清理確保在關(guān)閉應(yīng)用前終止所有虛擬線程,避免資源泄漏。可通過
Thread.ofVirtual().factory().allThreads()獲取所有虛擬線程并中斷。日志與監(jiān)控啟用虛擬線程后,建議配置日志記錄線程信息(如
%thread),以便區(qū)分平臺(tái)線程與虛擬線程。
結(jié)論
用戶提供的分析完全正確。虛擬線程的守護(hù)線程特性是導(dǎo)致非Web應(yīng)用提前退出的根本原因,而spring.main.keep-alive=true通過注入非守護(hù)線程有效解決了這一問題。此方案是Spring Boot官方推薦的標(biāo)準(zhǔn)做法,適用于需要長(zhǎng)期運(yùn)行后臺(tái)任務(wù)(如定時(shí)任務(wù)、消息消費(fèi))的非Web場(chǎng)景。
到此這篇關(guān)于Spring Boot3虛擬線程的使用步驟詳解的文章就介紹到這了,更多相關(guān)SpringBoot3虛擬線程使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java語言中finally是否一定會(huì)執(zhí)行你知道嗎
這篇文章主要為大家詳細(xì)介紹了Java finally是否一定會(huì)執(zhí)行,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02
springboot?整合?dubbo?的實(shí)現(xiàn)組聚合詳情
這篇文章主要介紹了springboot整合dubbo的實(shí)現(xiàn)組聚合詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07
關(guān)于Mybatis-Plus?Wrapper是否應(yīng)該出現(xiàn)在Servcie類中
最近在做代碼重構(gòu),代碼工程采用了Controller/Service/Dao分層架構(gòu),Dao層使用了Mybatis-Plus框架,本文帶領(lǐng)大家學(xué)習(xí)Mybatis-Plus?Wrapper應(yīng)該出現(xiàn)在Servcie類中嗎,需要的朋友可以參考下2023-05-05
Java接口操作(繼承父類并實(shí)現(xiàn)多個(gè)接口)
這篇文章主要介紹了Java接口操作(繼承父類并實(shí)現(xiàn)多個(gè)接口),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10
Java信號(hào)量Semaphore原理及代碼實(shí)例
這篇文章主要介紹了Java信號(hào)量Semaphore原理及代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
Java面向?qū)ο蟪绦蛟O(shè)計(jì)多態(tài)性示例
這篇文章主要介紹了Java面向?qū)ο蟪绦蛟O(shè)計(jì)多態(tài)性,結(jié)合實(shí)例形式分析了java多態(tài)性的概念、原理、定義與使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2018-03-03
java正則表達(dá)式判斷強(qiáng)密碼和隨機(jī)生成強(qiáng)密碼代碼示例
這篇文章主要給大家介紹了關(guān)于java正則表達(dá)式判斷強(qiáng)密碼和隨機(jī)生成強(qiáng)密碼的相關(guān)資料,最近需要一個(gè)密碼強(qiáng)度正則表達(dá)式在用戶注冊(cè)時(shí)校驗(yàn)用戶密碼強(qiáng)度,需要的朋友可以參考下2023-08-08
Javafx利用fxml變換場(chǎng)景的實(shí)現(xiàn)示例
本文主要介紹了Javafx利用fxml變換場(chǎng)景的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07

