SpringBoot實(shí)現(xiàn)虛擬線程的方案
什么是虛擬線程
虛擬線程是Java19開始增加的一個(gè)特性,和Golang的攜程類似,一個(gè)其它語(yǔ)言早就提供的、且如此實(shí)用且好用的功能,作為一個(gè)Java開發(fā)者,早就已經(jīng)望眼欲穿了。
虛擬線程和普通線程的區(qū)別
“虛擬”線程,望文生義,它是“假”的,它不直接調(diào)度操作系統(tǒng)的線程,而是由JVM再提供一層線程的接口抽象,由普通線程調(diào)度,即一個(gè)普通的操作系統(tǒng)線程可以調(diào)度成千上萬(wàn)個(gè)虛擬線程。
虛擬線程比普通線程的消耗要小得多得多,在內(nèi)存足夠的情況下,我們甚至可以創(chuàng)建上百萬(wàn)的虛擬線程,這在之前(Java19以前)是不可能的。
其實(shí)如果有用過(guò)akka的朋友們會(huì)發(fā)現(xiàn),其實(shí)兩者很相似,只不過(guò)使用akka是應(yīng)用程序來(lái)處理,而虛擬線程是JVM來(lái)處理,使用上更簡(jiǎn)潔且方便。
SpringBoot使用虛擬線程
下面我們會(huì)在SpringBoot中使用虛擬線程,將默認(rèn)的異步線程池和http處理線程池替換為虛擬線程,然后對(duì)比虛擬線程和普通線程的性能差異,你會(huì)發(fā)現(xiàn)差別就像馬車換高鐵,不是一個(gè)時(shí)代的東西。
配置
首先我們使用的Java版本是java-20.0.2-oracle,SpringBoot版本是3.1.2。
要在SpringBoot中使用虛擬線程很簡(jiǎn)單,增加如下配置即可:
/** * 配置是用于稍后測(cè)試,spring.virtual-thread=true是使用虛擬線程,false時(shí)還是使用默認(rèn)的普通線程 */ @Configuration @ConditionalOnProperty(prefix = "spring", name = "virtual-thread", havingValue = "true") public class ThreadConfig { @Bean public AsyncTaskExecutor applicationTaskExecutor() { return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor()); } @Bean public TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() { return protocolHandler -> { protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); }; } }
@Async性能對(duì)比
我們寫一個(gè)異步service,里面睡眠50ms,模擬MySQL或Redis等IO操作:
@Service public class AsyncService { /** * * @param countDownLatch 用于測(cè)試 */ @Async public void doSomething(CountDownLatch countDownLatch) throws InterruptedException { Thread.sleep(50); countDownLatch.countDown(); } }
最后測(cè)試類,很簡(jiǎn)單,就是循環(huán)調(diào)用這個(gè)方法10萬(wàn)次,計(jì)算所有方法執(zhí)行完成的消耗的時(shí)間:
@Test public void testAsync() throws InterruptedException { long start = System.currentTimeMillis(); int n = 100000; CountDownLatch countDownLatch = new CountDownLatch(n); for (int i = 0; i < n; i++) { asyncService.doSomething(countDownLatch); } countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println("耗時(shí):" + (end - start) + "ms"); }
普通線程耗時(shí):678秒左右,超過(guò)10分鐘了
虛擬線程耗時(shí):3.9秒!!
朋友們,接近200倍的性能差距??!
HTTP請(qǐng)求性能對(duì)比
讓我們?cè)倏纯磆ttp請(qǐng)求的對(duì)比,簡(jiǎn)單寫個(gè)get請(qǐng)求,里面什么也不做,一樣睡50ms,模擬IO操作:
@RequestMapping("/get") public Object get() throws Exception { Thread.sleep(50); return "ok"; }
然后我們使用jmeter請(qǐng)求接口,500個(gè)并發(fā)線程,運(yùn)行1萬(wàn)次,看看效果如何:
「普通線程:」
可以看到最小用時(shí)50ms,這個(gè)沒(méi)毛病,接口里面睡眠了50ms,但是不管是中位數(shù)還是90/95/99線都大于150ms了,這是因?yàn)橄到y(tǒng)線程是一個(gè)很昂貴的資源,SpringBoot中tomcat默認(rèn)的最大連接數(shù)應(yīng)該是200,在連接池的線程被耗盡后,這200個(gè)線程在那干等50ms結(jié)束,而剩下的請(qǐng)求也只能等待,無(wú)法進(jìn)行其它的操作。下面再看下虛擬線程的表現(xiàn):
「虛擬線程耗時(shí):」
可以看到即使是最大耗時(shí),也保持在100ms以下,即線程等待時(shí)間顯著的減少,虛擬線程更好的利用了系統(tǒng)資源。
總結(jié)
從上面的性能對(duì)比來(lái)看,虛擬線程在性能方面有明顯的優(yōu)勢(shì),但是要注意的是,我們上面的測(cè)試都是讓線程等待了50ms,這是模擬什么場(chǎng)景?
沒(méi)錯(cuò),是IO密集型場(chǎng)景,即線程大部分時(shí)間是在等待IO,這樣虛擬線程才可以發(fā)揮出它的優(yōu)勢(shì),如果是CPU密集型場(chǎng)景,那么可能效果并不大。不過(guò)我們目前大部分的應(yīng)用都是IO密集型應(yīng)用較多,比如典型的WEB應(yīng)用,大量的時(shí)間在等待網(wǎng)絡(luò)IO(DB、緩存、HTTP等等),使用虛擬線程的效果還是非常明顯的。
最后:大部分的公司可能還在用Java8,但是我想說(shuō)的是,是時(shí)候升級(jí)了,跟上時(shí)代的腳步吧,朋友們!
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)虛擬線程的方法步驟的文章就介紹到這了,更多相關(guān)SpringBoot 虛擬線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring+Vue整合UEditor富文本實(shí)現(xiàn)圖片附件上傳的方法
這篇文章主要介紹了Spring+Vue整合UEditor富文本實(shí)現(xiàn)圖片附件上傳的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07微信公眾號(hào)測(cè)試賬號(hào)自定義菜單的實(shí)例代碼
這篇文章主要介紹了微信公眾號(hào)測(cè)試賬號(hào)自定義菜單的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02SpringMVC+EasyUI實(shí)現(xiàn)頁(yè)面左側(cè)導(dǎo)航菜單功能
這篇文章主要介紹了SpringMVC+EasyUI實(shí)現(xiàn)頁(yè)面左側(cè)導(dǎo)航菜單功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09Java基礎(chǔ)之Thymeleaf的簡(jiǎn)單使用
這篇文章主要介紹了Java基礎(chǔ)之Thymeleaf的簡(jiǎn)單使用,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04Java8新特性O(shè)ptional類處理空值判斷回避空指針異常應(yīng)用
這篇文章主要介紹了Java8新特性O(shè)ptional類處理空值判斷回避空指針異常應(yīng)用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04springboot實(shí)現(xiàn)啟動(dòng)直接訪問(wèn)項(xiàng)目地址
這篇文章主要介紹了springboot實(shí)現(xiàn)啟動(dòng)直接訪問(wèn)項(xiàng)目地址,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java數(shù)據(jù)結(jié)構(gòu)之查找
本文主要介紹了Java數(shù)據(jù)結(jié)構(gòu)中查找的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03