平地起驚雷!!!
你可以稱呼它爲:JDK 8 之後的神,它也是很多人認爲的 JDK 8 之後,最值得升級的版本。
以前大家都說:
他發任他發,我用JAVA 8
抱歉,這次JDK 21 我不得不使用了
已知使用較爲廣泛的幾個 LTS版本是 (Long Term Support) :
- JDK 8 LTS
- JDK 11 LTS
- JDK 17 LTS
那麼爲什麼非得是 JDK 21呢?
英雄的遲暮
- ...
- Kafka 宣佈棄用 Java 8 ...
- Jenkins 宣佈棄用 Java 8 ...
- Spring6 強依賴 Java 17 ...
- Elasticsearch 使用的JDK 也不是 JDK8
- ......
JDK 8 的地位並非無可撼動的,如下所示爲某個機構統計的,近幾年一些線上 JAVA 應用使用的 JDK 版本情況:
-
LTS j8 已經從 84% 一路迭到了 32%
-
而另兩個 LTS 版本 J_11 和 J_17 的使用情況都有了長足的進步
所以別傻了,可能只有你在堅守JDK 8,你的小夥伴可能都已經轉投別人溫暖的懷抱了
JDK 21 LTS 可是迎來了史詩級的增強(後邊詳述),它的表現一定不會比 JDK_11 和 JDK_17弱。
spring系列作爲綁定JAVA的頭號玩家,期待Spring 的下一個大版本。
變革的大幕已經拉開,車輪已經開始滾滾先前; 昨日之日或西垂,奪目新日將大展光芒。
大人時代變了
JDK 21他來真的了,下邊是我們的主角閃亮登場:
曾經在JDK 19中作爲預覽的虛擬線程,在JDK 21 LTS 中成爲正式功能了
[PS * JDK 21 除了 虛擬線程 ,其實還有不少別的特性,但是我感覺都屬於真正的平平無奇的水平,只有 虛擬線程 值得大動干戈。]
猶記得曾經閱讀讀 《深入理解Java虛擬機》一書時,關於Java 併發編程模型的章節,瞭解了 JAVA 的併發編程模型現狀後,純純的 GoLang 薄紗啊,故此實引爲一大遺憾。當時書中提到 JAVA 官方啓動了 Loom 項目來彌補這一缺憾,當時都只覺得是在忽悠,這麼多年的問題了,哪兒能那麼容易解決呢,怕是畫了老大一個餅吧? 雖然是耿耿於懷,之後老長時間沒有關注它了,然後,突然某天看到JDK 21來了, 虛擬線程 成爲了正式功能了,當時看到這個消息時還是挺開心的
問題一: 不就是上下文切換麼,我配置好線程池不就夠了?
- 設置線程池在一定程度上,確實可以減少上下文切換,但是除了創建線程、線程銷燬,線程的生命週期中的其它操作呢?
問題二,屎山怎麼辦?
- 屎山沒必要動它,原樣維持唄,可別給我說你本地裝了 j21 之後j8 的項目就跑不起來了。
- 而且現在【微服務 + 容器平臺】那麼火爆,這同樣也是解決之道啊
JDK 21 LTS 前 JAVA併發編程模型
JAVA 21之前的版本,用戶態(JVM 態)下,JDK的併發編程模型的是,JVM線程與操作系統的內核線程 1:1 實現,缺點是在用戶態(JVM態)下的每一個線程的,掛起、喚醒、銷燬等調度操作,都會直接作用到操作系統的內核線程上。
- LWP (Light Weight Process) 輕量級進程, 也就是JDK 21 之前版本中 JAVA 線程了
- KLT (kernel Level Thread) 操作線程內核線程
LWP 與 KLT 之間是一對一的
從JVM 發起對內核線程的調度,相對來說是一個非常重的操作,資源消耗嚴重。
關於資源消耗,例如:
- LWP (輕量級進程) 會消耗一定的內核資源,比如內核線程的棧空間,因此操作系統支持的輕量級進程是有限的。
- 高損耗的內核線程調度,它直接影響高併發場景下,多個線程的執行效率,所以之前偶爾聽到流傳的一個說法: Java業務爲王,GoLang高併發稱雄。
JDK 21 LTS 中的 JAVA 併發編程模型
而到了JDK 21 LTS 中引入的 虛擬線程 呢,到了這裏併發編程模型的實現發生了變化:
JVM 態線程跟操作系統內核態線程不再 {1:1} 實現,而是 { [1 (操作系統內核線程)] : [N (JVM 虛擬線程 )] }。這樣在JVM態下,對每個 虛擬線程 的創建、調度、切換、銷燬等操作,不再直接高度依賴操作系統內核線程,所以高併發常見下,線程的執行效率會有很大提升。
- UT: user thread 用戶線程,也可以稱呼它:虛擬線程
其實 GoLang 的協程就是類似 虛擬線程 的東西;不過 JAVA 的 虛擬線程 跟 GoLang 的協程還是有區別的:
- GoLang 的協程支持跨核(cpu),內存管理更優
- Java 的虛擬線程不支持跨核,但是執行的效率更佳
具體要怎麼選擇,就是仁者見仁智者見智了。
回到前邊提到的關於線程池的問題上來
虛擬線程 VS 線程池
先明確兩個概念:
- 輕量級進程:也就是 JDK 21 之前的 JAVA 線程,它的上下文切換直接關聯到操作系統內核上。
- 虛擬線程:JDK 21 新特性,純JVM 用戶態下的東西,它的執行、調度... 等操作不會強關聯繫統內核
線程池大行其道的原因:
-
每個 輕量級進程 的創建,都會直接去操作,操作系統的內核線程,並競爭CPU 的時間分片。所以聰明的大佬們想到了一個辦法就是引入線程池,這樣就可以大量節省去調度操作系統內核線程,執行 輕量級進程 創建、線程註銷相關的操作開銷了。
-
JDK 21 之前 輕量級進程 自身佔用的內存很高,也是線程池能夠大行其道的原因之一,常見的64位的操作系統上一個 輕量級進程 默認佔用 1MB 的內存空間,算算你的機器能創建多少個 輕量級進程 吧。
但是即使有了線程池,還是指標不治本。 輕量級進程 除了創建、銷燬之外,還有:掛起、喚醒 ...... 等等一系列的操作的上下文切換還是要依賴操作系統內核來完成的。由於線程池是複用的,線程池的每個 輕量級進程 會經歷無數次的掛起、喚醒、執行CPU 時間分片, 直至 輕量級進程 被線程池踢除。
然後就是 虛擬線程 了,它徹底解決了這些難點問題:
- 基於用戶態實現的併發編程模型,決定了 虛擬線程 調度,不再強依賴系統內核
- 虛擬線程 空間佔用極小,默認只有幾百字節,在64位的系統上,比 輕量級進程 默認的 1MB 小了太多太多;同等內存佔用下,創建的 虛擬線程 數絕對很容易達到 輕量級進程 數的指數倍。
The Last
總結來說就是:
減少了直接對操作系統內核線程的調度,將併發模型從操作系統內核 {1:1} 實現,轉變爲 {1:N} 實現,虛擬線程將完全由 JVM 自管理,執行效率,資源利用率都將得到提升。
綜上所述直接吹爆 JDK 21,因爲從 虛擬線程 開始,Java 在高併發領域也獲得了入場券。越是瞭解JVM 併發編程的模型的人,越會知道 虛擬線程 的重量。
連擠牙膏式的 JDK 11 LTS 和 JDK 17 LTS 使用量都能上去,憑什麼作爲王牌的 JDK 21 LTS 會上不去?