千呼萬喚始出來 JDK 21 LTS, 久等了

bokerr發表於2023-09-26

平地起驚雷!!!

你可以稱呼它為: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 LTSJDK 17 LTS 使用量都能上去,憑什麼作為王牌的 JDK 21 LTS 會上不去?

相關文章