最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析Java中的虛擬線程

 更新時間:2023年10月27日 10:44:58   作者:翟睿  
在本篇文章中,小編將帶大家深入了解Java虛擬線程的原理、如何使用、使用的注意事項以及其他相似技術的差別,感興趣的小伙伴可以跟隨小編一起學習一下

在最近發(fā)布的JDK 21 LTS版本中,加入了許多新特性。其中對我們開發(fā)人員影響最大的應該是分代ZGC以及Java的虛擬線程。在本篇文章中,我將帶大家深入了解Java虛擬線程的原理、如何使用、使用的注意事項以及其他相似技術的差別。

什么是虛擬線程

首先,我們需要了解什么是虛擬線程。

在平時的開發(fā)過程中,我們所使用的多線程往往意味著平臺線程。平臺線程代表著JVM直接與操作系統(tǒng)交互,創(chuàng)建了一個一個的線程,并且在JVM中還要為這個線程單獨開辟內(nèi)存使用。一般在JVM中創(chuàng)建一個平臺線程,開銷大約在1M左右。為了避免創(chuàng)建線程和銷毀線程帶來的巨大開銷,我們通常選擇使用池化技術來維護一些活躍的線程。

此外,線程的數(shù)量也需要嚴格控制。如果在一個線程池中維護成千上百個線程,往往效率并不盡如人意。因為線程在切換時涉及到CPU上下文的切換,如果線程數(shù)過多,反而會降低執(zhí)行效率。因此,如何控制線程池的大小也是考驗工程師經(jīng)驗的難點。

平臺線程與系統(tǒng)線程關系如下

為了解決這個問題,虛擬線程應運而生,虛擬線程并不是Java的首創(chuàng),它在很多其他語言中被稱為協(xié)程、纖程、綠色線程、用戶態(tài)線程等,虛擬線程相對平臺線程,并不直接與操作系統(tǒng)交互,虛擬線程的數(shù)據(jù)是維護在堆內(nèi)存中,由JVM創(chuàng)建的平臺線程來持有,由平臺線程來決定什么時候來切換虛擬線程,大概圖如下

雖然圖中只畫了幾個虛擬線程,但是在實際使用中,我們可以創(chuàng)建成百上千的虛擬線程而不用擔心資源消耗的問題

首先原因在于虛擬線程的開銷極其廉價,一個虛擬線程可能才使用幾百字節(jié),所以幾遍創(chuàng)建成百上千也不會消耗太多內(nèi)存資源

其次雖然我們有極多的虛擬線程,但是實際上執(zhí)行線程依舊只有幾個平臺線程,所以在線程使用中不會由于CPU上下文的切換導致的額外開銷。

使用

接下來我們用代碼來實踐一下虛擬線程,JDK的工程師為了方便我們快速進行虛擬線程的升級,可以使用Thread來快速創(chuàng)建虛擬線程

Thread vt = Thread.startVirtualThread(() -> {
    Thread.sleep(1000);
});

這種方法創(chuàng)建的虛擬線程會立刻啟動,那么如果我們想創(chuàng)建一個需要手動啟動的虛擬線程,可以參考如下的方式

// 創(chuàng)建VirtualThread
Thread.ofVirtual().unstarted(() -> {
    Thread.sleep(1000);
});
// 運行
vt.start();

還可以創(chuàng)建虛擬線程的工廠來使用

// 創(chuàng)建ThreadFactory:
ThreadFactory tf = Thread.ofVirtual().factory();
// 創(chuàng)建VirtualThread:
Thread vt = tf.newThread(() -> {
    Thread.sleep(1000);
});
// 運行:
vt.start();

我們將線程的上下文信息打印出來看看

VirtualThread[#21]/runnable@ForkJoinPool-1-worker-1

從這個打印內(nèi)容可以大概看出,虛擬線程底層采用了ForkJoinPool來維護平臺線程,而后面的worker-1則代表具體的平臺線程的名稱,前面的#21代表當前虛擬線程的數(shù)量,那么可能有同學就會問了 那如果我全局有成千上百個虛擬線程,我怎么知道是哪塊業(yè)務的線程除了問題呢。

我們可以對線程工廠進行命名,使用該線程工廠命名后,在線程上下文中就會打印對應虛擬線程工廠的信息。

ThreadFactory factory = Thread.ofVirtual().name("myVirtual").factory();
        try(ExecutorService executor = Executors.newThreadPerTaskExecutor(factory)) {
            for (int i=0; i<100000; i++) {
                // 也可以直接傳入Runnable或Callable:
                executor.submit(() -> {
                    System.out.println(Thread.currentThread());
                    Thread.sleep(1000);
                    return true;
                });
            }
        }

VirtualThread[#23,myVirtual]/runnable@ForkJoinPool-1-worker-2
VirtualThread[#275,myVirtual]/runnable@ForkJoinPool-1-worker-7
VirtualThread[#282,myVirtual]/runnable@ForkJoinPool-1-worker-5
VirtualThread[#285,myVirtual]/runnable@ForkJoinPool-1-worker-4
VirtualThread[#288,myVirtual]/runnable@ForkJoinPool-1-worker-3
VirtualThread[#234,myVirtual]/runnable@ForkJoinPool-1-worker-10

從日志中不難看出,我們已經(jīng)成功在線程上下文標記了這一塊虛擬線程屬于哪個工廠,并且通過信息后綴中的worker-10可以看出底層的ForkJoinPool已經(jīng)創(chuàng)建了10個平臺線程來操作虛擬線程,因為我這臺電腦是10核的,所以底層的線程池會創(chuàng)建與核心數(shù)相等的線程來操作虛擬線程,在我的實踐中發(fā)現(xiàn),無論你創(chuàng)建多少調(diào)度器,所有底層的虛擬線程都是由同一個平臺線程池來操控的。

而且在示例代碼中,我創(chuàng)建了十萬個虛擬線程,如果我是用的是平臺線程,且不說執(zhí)行效率,但是內(nèi)存分配就已經(jīng)使項目OOM了。

注意事項

ThreadLocal支持

有同學可能會問,在虛擬線程中能否使用ThreadLocal對象呢?官方給出的答案是,能夠使用但不建議。在過去,我們在維護線程池時,線程的數(shù)量是固定的且相對較少。我們通過手動清理的方式來重用ThreadLocal對象。然而,在使用虛擬線程后,我們不再關注具體的線程數(shù),這導致ThreadLocal對象的數(shù)量無法控制,從而占用了額外的內(nèi)存。需要注意的是,虛擬線程與平臺線程不共享同一個ThreadLocal。

永遠不要池化虛擬線程

之前我們提到過,虛擬線程的開銷非常低,每個虛擬線程可能只消耗幾百字節(jié)的內(nèi)存。這意味著我們不需要為虛擬線程創(chuàng)建所謂的線程池。相應地,根據(jù)我們之前的編碼習慣,如果某個功能只能接受20個并發(fā)請求,我們可能會創(chuàng)建一個固定大小為20的線程池來進行限流。然而,如果使用虛擬線程,我們應盡量改用類似信號量的方式來實現(xiàn)。

協(xié)程、IO多路復用與虛擬線程的關系

有很多同學可能對對這幾個概念相對比較混淆,我們可以來梳理下這幾個概念之間的異同,首先協(xié)程與虛擬線程從概念上是相同的,只是不同語言之間的實現(xiàn)方式是不同的,都是在用戶態(tài)線程中維護多個子線程進行切換,只是如Python語言可能需要手動去喚起協(xié)程,而Java中的虛擬線程都是交由JVM調(diào)度的。

而IO多路復用,我們以Netty為例,它內(nèi)部使用了IO多路復用技術來管理和處理大量的并發(fā)IO操作。Netty的IO多路復用機制可以有效地管理和調(diào)度多個連接,提高系統(tǒng)的吞吐量和性能。它基于事件驅(qū)動的設計模型,通過選擇器(Selector)來同時監(jiān)控多個IO通道的狀態(tài),當有IO事件就緒時,通過回調(diào)機制來進行處理。而虛擬線程通常用于解決IO阻塞的問題,通過在IO操作或時間等待點上主動釋放執(zhí)行權(quán),來實現(xiàn)更好的并發(fā)性能。虛擬線程可以減少線程切換的開銷,但它仍然是在應用程序內(nèi)部執(zhí)行的,并不能直接替代IO多路復用來管理和處理大量的并發(fā)IO操作。可以說術業(yè)有專攻,但是虛擬線程確實會對多IO操作有效率提升的。

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

相關文章

  • java中深復制知識點詳解

    java中深復制知識點詳解

    在本篇文章里小編給大家整理了關于java中深復制知識點詳解內(nèi)容,有需要的朋友們可以學習下。
    2020-12-12
  • Java程序員必備的11大IntelliJ插件(附地址)

    Java程序員必備的11大IntelliJ插件(附地址)

    這篇文章主要介紹了Java程序員必備的11大IntelliJ插件(附地址),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • MySQL查詢字段實現(xiàn)字符串分割split功能的示例代碼

    MySQL查詢字段實現(xiàn)字符串分割split功能的示例代碼

    本文主要介紹了MySQL查詢字段實現(xiàn)字符串分割split功能的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java注解Annotaton詳解

    Java注解Annotaton詳解

    Java 注解(Annotation)又稱 Java 標注,是 JDK5.0 引入的一種注釋機制,文中給大家介紹了三種基本的Annotaton,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2022-05-05
  • Java項目Guava包?HashMultimap使用及注意事項

    Java項目Guava包?HashMultimap使用及注意事項

    guava基本上可以說是java開發(fā)項目中,大概率會引入的包,今天介紹的主角是一個特殊的容器HashMultmap,可以簡單的將它的數(shù)據(jù)結(jié)構(gòu)理解為Map<K,?Set<V>>,今天主要介紹下基礎的知識點?HashMultmap級使用,感興趣的朋友一起看看吧
    2022-05-05
  • java中BigDecimal里面的subtract函數(shù)介紹及實現(xiàn)方法

    java中BigDecimal里面的subtract函數(shù)介紹及實現(xiàn)方法

    在Java中實現(xiàn)減法操作需要根據(jù)數(shù)據(jù)類型選擇不同方法,主要分為數(shù)值型減法和字符串減法兩種場景,本文給大家介紹java中BigDecimal里面的subtract函數(shù)及實現(xiàn)方法,感興趣的朋友一起看看吧
    2025-06-06
  • Java數(shù)據(jù)結(jié)構(gòu)之常見排序算法(上)

    Java數(shù)據(jù)結(jié)構(gòu)之常見排序算法(上)

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之常見排序算法,本文章是匯總篇,且對每個排序都進行了說明,可以很好的理清思路,對排序算法有個總體的框架,需要的朋友可以參考下
    2023-01-01
  • nacos服務注冊命名空間指定方式

    nacos服務注冊命名空間指定方式

    文章介紹了Nacos服務注冊命名空間的用途,以及如何創(chuàng)建和指定命名空間,命名空間用于隔離不同項目的服務和配置,避免沖突,通過在配置文件中指定命名空間ID,服務會注冊到相應的命名空間中,這樣可以更好地管理不同環(huán)境下的配置文件
    2024-12-12
  • 解決OOM:JVM內(nèi)存不足問題

    解決OOM:JVM內(nèi)存不足問題

    這篇文章主要介紹了解決OOM:JVM內(nèi)存不足問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • 在idea中git pull失敗的解決方案

    在idea中git pull失敗的解決方案

    在遇到Git Pull失敗時,首先使用IDEA的git-revert功能進行還原,然后檢查并解決分支沖突,最后重新執(zhí)行Git Pull確保所有文件是最新的,注意,在操作過程中確保網(wǎng)絡連接正常,并且每步操作后都要執(zhí)行Git Pull來更新數(shù)據(jù)
    2024-10-10

最新評論

南部县| 自治县| 天柱县| 清远市| 长春市| 东丰县| 武陟县| 乳山市| 金华市| 黄平县| 石狮市| 临高县| 苍溪县| 建平县| 乐昌市| 甘泉县| 张家界市| 文山县| 金溪县| 油尖旺区| 江北区| 万山特区| 子洲县| 红桥区| 乌拉特中旗| 潼南县| 凌海市| 澄迈县| 新邵县| 平果县| 临澧县| 浙江省| 南郑县| 宁德市| 甘德县| 沅陵县| 开化县| 綦江县| 松江区| 抚松县| 兰西县|