科技與狠活?JDK19中的虛擬線程到底什么鬼?
本文給大家介紹了一下JDK 19新推出的虛擬線程,或者叫協(xié)程,主要是為了解決在讀書(shū)操作系統(tǒng)中線程需要依賴(lài)內(nèi)核線程的實(shí)現(xiàn),導(dǎo)致有很多額外開(kāi)銷(xiāo)的問(wèn)題。通過(guò)在Java語(yǔ)言層面引入虛擬線程,通過(guò)JVM進(jìn)行調(diào)度管理,從而減少上下文切換的成本。
?最近,JDK 19發(fā)布了,推出了幾個(gè)新的特性,其中有一個(gè)比較值得關(guān)注的那就是新增了虛擬線程。
【資料圖】
很多人可能比較疑惑,到底什么是虛擬線程,和我們現(xiàn)在使用的平臺(tái)線程有啥區(qū)別呢?
要說(shuō)清楚JDK 19中的虛擬線程,我們要先來(lái)了解一下線程都是怎么實(shí)現(xiàn)的。
線程的實(shí)現(xiàn)方式
我們都知道,在操作系統(tǒng)中,線程是比進(jìn)程更輕量級(jí)的調(diào)度執(zhí)行單位,線程的引入可以把一個(gè)進(jìn)程的資源分配和執(zhí)行調(diào)度分開(kāi),各個(gè)線程既可以共享進(jìn)程資源,又可以獨(dú)立調(diào)度。
其實(shí),線程的實(shí)現(xiàn)方式主要有三種:分別是使用內(nèi)核線程實(shí)現(xiàn)、使用用戶(hù)線程實(shí)現(xiàn)以及使用用戶(hù)線程加輕量級(jí)進(jìn)程混合實(shí)現(xiàn)。
使用內(nèi)核線程實(shí)現(xiàn)
內(nèi)核線程(Kernel-Level Thread,KLT)就是直接由操作系統(tǒng)內(nèi)核(Kernel,下稱(chēng)內(nèi)核)支持的線程,這種線程由內(nèi)核來(lái)完成線程切換,內(nèi)核通過(guò)操縱調(diào)度器(Scheduler)對(duì)線程進(jìn)行調(diào)度,并負(fù)責(zé)將線程的任務(wù)映射到各個(gè)處理器上,并向應(yīng)用程序提供API接口來(lái)管理線程。
應(yīng)用程序一般不會(huì)直接去使用內(nèi)核線程,而是去使用內(nèi)核線程的一種高級(jí)接口——輕量級(jí)進(jìn)程(Light Weight Process,LWP),輕量級(jí)進(jìn)程就是我們通常意義上所講的線程,由于每個(gè)輕量級(jí)進(jìn)程都由一個(gè)內(nèi)核線程支持,因此只有先支持內(nèi)核線程,才能有輕量級(jí)進(jìn)程。
有了內(nèi)核線程的支持,每個(gè)輕量級(jí)進(jìn)程都成為一個(gè)獨(dú)立的調(diào)度單元,即使有一個(gè)輕量級(jí)進(jìn)程在系統(tǒng)調(diào)用中阻塞了,也不會(huì)影響整個(gè)進(jìn)程繼續(xù)工作。
但是輕量級(jí)進(jìn)程具有它的局限性:首先,由于是基于內(nèi)核線程實(shí)現(xiàn)的,所以各種線程操作,如創(chuàng)建、析構(gòu)及同步,都需要進(jìn)行系統(tǒng)調(diào)用。而系統(tǒng)調(diào)用的代價(jià)相對(duì)較高,需要在用戶(hù)態(tài)(User Mode)和內(nèi)核態(tài)(Kernel Mode)中來(lái)回切換。其次,每個(gè)輕量級(jí)進(jìn)程都需要有一個(gè)內(nèi)核線程的支持,因此輕量級(jí)進(jìn)程要消耗一定的內(nèi)核資源(如內(nèi)核線程的??臻g),因此一個(gè)系統(tǒng)支持輕量級(jí)進(jìn)程的數(shù)量是有限的。
使用用戶(hù)線程實(shí)現(xiàn)
在用戶(hù)空間建立線程庫(kù),通過(guò)運(yùn)行時(shí)系統(tǒng)(Run-time System)來(lái)完成線程的管理,因?yàn)檫@種線程的實(shí)現(xiàn)是在用戶(hù)空間的,所以操作系統(tǒng)的內(nèi)核并不知道線程的存在,所以?xún)?nèi)核管理的還是進(jìn)程,所以這種線程的切換不需要內(nèi)核操作。
這種實(shí)現(xiàn)方式下,一個(gè)進(jìn)程和線程之間的關(guān)系是一對(duì)多的。
這種線程實(shí)現(xiàn)方式的優(yōu)點(diǎn)是線程切換快,并且可以運(yùn)行在任何操作系統(tǒng)之上,只需要實(shí)現(xiàn)線程庫(kù)就行了。但是缺點(diǎn)也比較明顯,就是所有線程的操作都需要用戶(hù)程序自己處理,并且因?yàn)榇蠖鄶?shù)系統(tǒng)調(diào)用都是阻塞的,所以一旦一個(gè)進(jìn)程阻塞了,那么進(jìn)程中的所有線程也會(huì)被阻塞。還有就是多處理器系統(tǒng)中如何將線程映射到其他處理器上也是一個(gè)比較大的問(wèn)題。
使用用戶(hù)線程加輕量級(jí)進(jìn)程混合實(shí)現(xiàn)
還有一種混合實(shí)現(xiàn)的方式,就是線程的創(chuàng)建在用戶(hù)空間完成,通過(guò)線程庫(kù)進(jìn)行,但是線程的調(diào)度是由內(nèi)核來(lái)完成的。多個(gè)用戶(hù)線程通過(guò)多路復(fù)用來(lái)復(fù)用多個(gè)內(nèi)核線程。這個(gè)就不展開(kāi)講了
Java線程的實(shí)現(xiàn)方式
以上講的是操作系統(tǒng)的線程的實(shí)現(xiàn)的三種方式,不同的操作系統(tǒng)在實(shí)現(xiàn)線程的時(shí)候會(huì)采用不同的機(jī)制,比如windows采用的是內(nèi)核線程實(shí)現(xiàn)的,而Solaris則是通過(guò)混合模式實(shí)現(xiàn)的。
而Java作為一門(mén)跨平臺(tái)的編程語(yǔ)言,實(shí)際上他的線程的實(shí)現(xiàn)其實(shí)是依賴(lài)具體的操作系統(tǒng)的。而比較常用的windows和linux來(lái)說(shuō),都是采用內(nèi)核線程的方式實(shí)現(xiàn)的。
也就是說(shuō),當(dāng)我們?cè)贘AVA代碼中創(chuàng)建一個(gè)Tread的時(shí)候,其實(shí)是需要映射到操作系統(tǒng)的線程的具體實(shí)現(xiàn)的,因?yàn)槌R?jiàn)的通過(guò)內(nèi)核線程實(shí)現(xiàn)的方式在創(chuàng)建、調(diào)度時(shí)都需要進(jìn)行內(nèi)核參與,所以成本比較高,盡管JAVA中提供了線程池的方式來(lái)避免重復(fù)創(chuàng)建線程,但是依舊有很大的優(yōu)化空間。而且這種實(shí)現(xiàn)方式意味著受機(jī)器資源的影響,平臺(tái)線程數(shù)也是有限制的。
虛擬線程
JDK 19引入的虛擬線程,是JDK 實(shí)現(xiàn)的輕量級(jí)線程,他可以避免上下文切換帶來(lái)的的額外耗費(fèi)。他的實(shí)現(xiàn)原理其實(shí)是JDK不再是每一個(gè)線程都一對(duì)一的對(duì)應(yīng)一個(gè)操作系統(tǒng)的線程了,而是會(huì)將多個(gè)虛擬線程映射到少量操作系統(tǒng)線程中,通過(guò)有效的調(diào)度來(lái)避免那些上下文切換。
而且,我們可以在應(yīng)用程序中創(chuàng)建非常多的虛擬線程,而不依賴(lài)于平臺(tái)線程的數(shù)量。這些虛擬線程是由JVM管理的,因此它們不會(huì)增加額外的上下文切換開(kāi)銷(xiāo),因?yàn)樗鼈冏鳛槠胀↗ava對(duì)象存儲(chǔ)在RAM中。
虛擬線程與平臺(tái)線程的區(qū)別
首先,虛擬線程總是守護(hù)線程。setDaemon (false)方法不能將虛擬線程更改為非守護(hù)線程。所以,需要注意的是,當(dāng)所有啟動(dòng)的非守護(hù)進(jìn)程線程都終止時(shí),JVM將終止。這意味著JVM不會(huì)等待虛擬線程完成后才退出。
其次,即使使用setPriority()方法,虛擬線程始終具有normal的優(yōu)先級(jí),且不能更改優(yōu)先級(jí)。在虛擬線程上調(diào)用此方法沒(méi)有效果。
還有就是,虛擬線程是不支持stop()、suspend()或resume()等方法。這些方法在虛擬線程上調(diào)用時(shí)會(huì)拋出UnsupportedOperationException異常。
如何使用虛擬線程
接下來(lái)介紹一下,在JDK 19中如何使用虛擬線程。
首先,通過(guò)Thread.startVirtualThread()可以運(yùn)行一個(gè)虛擬線程:
Thread.startVirtualThread(() -> { System.out.println("虛擬線程執(zhí)行中...");});
其次,通過(guò)Thread.Builder也可以創(chuàng)建虛擬線程,Thread類(lèi)提供了ofPlatform()來(lái)創(chuàng)建一個(gè)平臺(tái)線程、ofVirtual()來(lái)創(chuàng)建虛擬現(xiàn)場(chǎng)。
Thread.Builder platformBuilder = Thread.ofPlatform().name("平臺(tái)線程");Thread.Builder virtualBuilder = Thread.ofVirtual().name("虛擬線程");Thread t1 = platformBuilder .start(() -> {...}); Thread t2 = virtualBuilder.start(() -> {...});
另外,線程池也支持了虛擬線程,可以通過(guò)Executors.newVirtualThreadPerTaskExecutor()來(lái)創(chuàng)建虛擬線程:
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { IntStream.range(0, 10000).forEach(i -> { executor.submit(() -> { Thread.sleep(Duration.ofSeconds(1)); return i; }); });}
但是,其實(shí)并不建議虛擬線程和線程池一起使用,因?yàn)镴ava線程池的設(shè)計(jì)是為了避免創(chuàng)建新的操作系統(tǒng)線程的開(kāi)銷(xiāo),但是創(chuàng)建虛擬線程的開(kāi)銷(xiāo)并不大,所以其實(shí)沒(méi)必要放到線程池中。
性能差異
說(shuō)了半天,虛擬線程到底能不能提升性能,能提升多少呢?我們來(lái)做個(gè)測(cè)試。
我們寫(xiě)一個(gè)簡(jiǎn)單的任務(wù),在控制臺(tái)中打印消息之前等待1秒:
final AtomicInteger atomicInteger = new AtomicInteger();Runnable runnable = () -> { try { Thread.sleep(Duration.ofSeconds(1)); } catch(Exception e) { System.out.println(e); } System.out.println("Work Done - " + atomicInteger.incrementAndGet());};
現(xiàn)在,我們將從這個(gè)Runnable創(chuàng)建10,000個(gè)線程,并使用虛擬線程和平臺(tái)線程執(zhí)行它們,以比較兩者的性能。
先來(lái)我們比較熟悉的平臺(tái)線程的實(shí)現(xiàn):
Instant start = Instant.now();try (var executor = Executors.newFixedThreadPool(100)) { for(int i = 0; i < 10_000; i++) { executor.submit(runnable); }}Instant finish = Instant.now();long timeElapsed = Duration.between(start, finish).toMillis(); System.out.println("總耗時(shí) : " + timeElapsed);
輸出結(jié)果為:
總耗時(shí) : 102323
總耗時(shí)大概100秒左右。接下來(lái)再用虛擬線程跑一下看看
因?yàn)樵贘DK 19中,虛擬線程是一個(gè)預(yù)覽API,默認(rèn)是禁用。所以需要使用$ java——source 19——enable-preview xx.java 的方式來(lái)運(yùn)行代碼。?
Instant start = Instant.now();try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { for(int i = 0; i < 10_000; i++) { executor.submit(runnable); }}Instant finish = Instant.now();long timeElapsed = Duration.between(start, finish).toMillis(); System.out.println("總耗時(shí) : " + timeElapsed);
使用 Executors.newVirtualThreadPerTaskExecutor()來(lái)創(chuàng)建虛擬線程,執(zhí)行結(jié)果如下:
總耗時(shí) : 1674
總耗時(shí)大概1.6秒左右。
100秒和1.6秒的差距,足以看出虛擬線程的性能提升還是立竿見(jiàn)影的。
總結(jié)
本文給大家介紹了一下JDK 19新推出的虛擬線程,或者叫協(xié)程,主要是為了解決在讀書(shū)操作系統(tǒng)中線程需要依賴(lài)內(nèi)核線程的實(shí)現(xiàn),導(dǎo)致有很多額外開(kāi)銷(xiāo)的問(wèn)題。通過(guò)在Java語(yǔ)言層面引入虛擬線程,通過(guò)JVM進(jìn)行調(diào)度管理,從而減少上下文切換的成本。
同時(shí)我們經(jīng)過(guò)簡(jiǎn)單的demo測(cè)試,發(fā)現(xiàn)虛擬線程的執(zhí)行確實(shí)高效了很多。但是使用的時(shí)候也需要注意,虛擬線程是守護(hù)線程,所以有可能會(huì)沒(méi)等他執(zhí)行完虛擬機(jī)就會(huì)shutdown掉。
參考資料:
https://openjdk.org/jeps/425
https://howtodoinjava.com/java/multi-threading/virtual-threads/
關(guān)鍵詞:
相關(guān)閱讀
-
科技與狠活?JDK19中的虛擬線程到底什么鬼?
本文給大家介紹了一下JDK19新推出的虛擬線程,或者叫協(xié)程,主要是為... -
男子沙漠迷路120小時(shí) 民警用無(wú)人機(jī)成功營(yíng)救
男子沙漠迷路120小時(shí)民警用無(wú)人機(jī)成功營(yíng)救,公安局,無(wú)人機(jī),尉犁縣,沙漠迷路 -
個(gè)稅速算扣除數(shù)是什么?速算扣除數(shù)怎么...
個(gè)稅速算扣除數(shù)是什么?速算扣除數(shù)是個(gè)人所得稅中用來(lái)修正個(gè)稅計(jì)算中... -
二甲氨基乙醇酒石酸氫鹽添加量(二甲氨...
當(dāng)前大家對(duì)于二甲氨基乙醇酒石酸氫鹽都是頗為感興趣的,大家都想要... -
HD Audio 是什么
高清音頻(HDaudio)是指錄制音樂(lè)時(shí)使用的高帶寬音頻信號(hào)。不同的軟件... -
無(wú)形資產(chǎn)攤銷(xiāo)年限是什么?怎樣進(jìn)行無(wú)形...
無(wú)形資產(chǎn)攤銷(xiāo)年限是什么?無(wú)形資產(chǎn)攤銷(xiāo)年限:一般情況下,無(wú)形資產(chǎn)攤... -
惡人報(bào)喜迅雷下載 1080p 下載_惡人報(bào)...
1、后,才趴在他的胸膛上,一邊畫(huà)著圈圈一邊說(shuō)的。2、“我當(dāng)集團(tuán)副... -
我不知道我怎么了我還在期待是什么歌-天...
現(xiàn)在許多熱門(mén)歌曲都會(huì)被作為一段視頻的背景音樂(lè)出現(xiàn),由于都是一小... -
剛漲完價(jià),特斯拉Model S又推出賽道套...
5月6日消息,特斯拉ModelSPlaid將提供新的賽道套件,可以大幅提升車(chē)... -
權(quán)責(zé)發(fā)生制和收付實(shí)現(xiàn)制有什么區(qū)別?權(quán)...
權(quán)責(zé)發(fā)生制和收付實(shí)現(xiàn)制有什么區(qū)別?1、概念不同:權(quán)責(zé)發(fā)生制是相對(duì)... -
什么是發(fā)票?發(fā)票管理辦法是什么?發(fā)票...
什么是發(fā)票?發(fā)票是指一切單位和個(gè)人在購(gòu)銷(xiāo)商品、提供勞務(wù)或接受勞務(wù)... -
汽車(chē)購(gòu)置稅怎么算?2023購(gòu)置稅還會(huì)減半嗎?
汽車(chē)購(gòu)置稅怎么算?汽車(chē)購(gòu)置稅計(jì)算公式:購(gòu)置稅=計(jì)稅價(jià)格×10%(... -
【全球時(shí)快訊】紹興數(shù)智產(chǎn)業(yè)園正式啟動(dòng)
4月27日,紹興數(shù)智產(chǎn)業(yè)園項(xiàng)目啟動(dòng)儀式在紹興舉行。首批入園企業(yè)代表... -
每日速遞:從“淄博燒烤”到“青年與海...
辯論賽你來(lái)我往,唇槍舌劍,總是閃爍著思辨的智慧。5月3日晚,浙江... -
深入交流 探討糖尿病管理模式創(chuàng)新 —...
點(diǎn)擊藍(lán)字關(guān)注我們4月15日,梨園社區(qū)衛(wèi)生服務(wù)中心主任甘靜雯受邀在第... -
百融智匯云:發(fā)揮“智能路由”優(yōu)勢(shì) 助...
近年來(lái),全球經(jīng)濟(jì)發(fā)展中,人工智能、大數(shù)據(jù)、云計(jì)算和區(qū)塊鏈等前沿... -
天天短訊!慢性腸炎吃什么、禁什么呢?
腸炎是細(xì)菌、病毒、真菌和寄生蟲(chóng)等引起的小腸炎和結(jié)腸炎。臨床表現(xiàn)... -
市盈率是什么意思?市盈率800倍意味著什么?
市盈率是什么意思?市盈率也稱(chēng)本益比、股價(jià)收益比率或市價(jià)盈利比率。... -
cma是什么證書(shū)?cma的報(bào)考條件和費(fèi)用是什么?
cma是什么證書(shū)?CMA證書(shū)是美國(guó)注冊(cè)管理會(huì)計(jì)師(Certified Management... -
國(guó)內(nèi)冠軍宣布加入日本聯(lián)賽,將與張本智...
周雨也是有一定實(shí)力的,雖然已經(jīng)退役了,但是他和閆安、方博“92一...