Java 19 已至,虛擬線程 = 王炸!!
近期文章精選 :
JDK 19 定于 9 月 20 日正式發(fā)布以供生產(chǎn)使用,非長(zhǎng)期支持版本。不過(guò),JDK 19 中有一些比較重要的新特性值得關(guān)注。
JDK 19 只有 7 個(gè)新特性:
- JEP 405: Record Patterns(記錄模式)[1](預(yù)覽)
- JEP 422: Linux/RISC-V Port [2]
- JEP 424: Foreign Function & Memory API(外部函數(shù)和內(nèi)存 API)[3](預(yù)覽)
- JEP 425: Virtual Threads(虛擬線程)[4](預(yù)覽)
- JEP 426: Vector(向量)API[5](第四次孵化)
- JEP 427: Pattern Matching for switch(switch 模式匹配) [6]
- JEP 428: Structured Concurrency(結(jié)構(gòu)化并發(fā))[7](孵化)
這里只對(duì) 424、425、426、428 這 4 個(gè)我覺(jué)得比較重要的新特性進(jìn)行詳細(xì)介紹。
JEP 424: 外部函數(shù)和內(nèi)存 API(預(yù)覽)
Java 程序可以通過(guò)該 API 與 Java 運(yùn)行時(shí)之外的代碼和數(shù)據(jù)進(jìn)行互操作。通過(guò)高效地調(diào)用外部函數(shù)(即 JVM 之外的代碼)和安全地訪問(wèn)外部?jī)?nèi)存(即不受 JVM 管理的內(nèi)存),該 API 使 Java 程序能夠調(diào)用本機(jī)庫(kù)并處理本機(jī)數(shù)據(jù),而不會(huì)像 JNI 那樣危險(xiǎn)和脆弱。
外部函數(shù)和內(nèi)存 API 之前在 JDK 17 中孵化,在 JDK 18 中重新孵化。
在沒(méi)有外部函數(shù)和內(nèi)存 API 之前:
-
Java 通過(guò) `sun.misc.Unsafe`[8] 提供一些執(zhí)行低級(jí)別、不安全操作的方法(如直接訪問(wèn)系統(tǒng)內(nèi)存資源、自主管理內(nèi)存資源等),
Unsafe類(lèi)讓 Java 語(yǔ)言擁有了類(lèi)似 C 語(yǔ)言指針一樣操作內(nèi)存空間的能力的同時(shí),也增加了 Java 語(yǔ)言的不安全性,不正確使用Unsafe類(lèi)會(huì)使得程序出錯(cuò)的概率變大。 - Java 1.1 就已通過(guò) Java 原生接口(JNI)支持了原生方法調(diào)用,但并不好用。JNI 實(shí)現(xiàn)起來(lái)過(guò)于復(fù)雜,步驟繁瑣(具體的步驟可以參考這篇文章:Guide to JNI (Java Native Interface)[9] ),不受 JVM 的語(yǔ)言安全機(jī)制控制,影響 Java 語(yǔ)言的跨平臺(tái)特性。并且,JNI 的性能也不行,因?yàn)?JNI 方法調(diào)用不能從許多常見(jiàn)的 JIT 優(yōu)化(如內(nèi)聯(lián))中受益。雖然JNA[10]、JNR[11]和JavaCPP[12]等框架對(duì) JNI 進(jìn)行了改進(jìn),但效果還是不太理想。
引入外部函數(shù)和內(nèi)存 API 就是為了解決 Java 訪問(wèn)外部函數(shù)和外部?jī)?nèi)存存在的一些痛點(diǎn)。
Foreign Function & Memory API (FFM API) 定義了類(lèi)和接口:
-
分配外部?jī)?nèi)存 :
MemorySegment、、MemoryAddress和SegmentAllocator); -
操作和訪問(wèn)結(jié)構(gòu)化的外部?jī)?nèi)存:
MemoryLayout,VarHandle; -
控制外部?jī)?nèi)存的分配和釋放:
MemorySession; -
調(diào)用外部函數(shù):
Linker、FunctionDescriptor和SymbolLookup。
下面是 FFM API 使用示例,這段代碼獲取了 C 庫(kù)函數(shù)的 radixsort 方法句柄,然后使用它對(duì) Java 數(shù)組中的四個(gè)字符串進(jìn)行排序。

JEP 425: 虛擬線程(預(yù)覽)
虛擬線程是 JDK 而不是 OS 實(shí)現(xiàn)的輕量級(jí)線程(Lightweight Process,LWP),許多虛擬線程共享同一個(gè)操作系統(tǒng)線程,虛擬線程的數(shù)量可以遠(yuǎn)大于操作系統(tǒng)線程的數(shù)量。
虛擬線程在其他多線程語(yǔ)言中已經(jīng)被證實(shí)是十分有用的,比如 Go 中的 Goroutine、Erlang 中的進(jìn)程。
虛擬線程避免了上下文切換的額外耗費(fèi),兼顧了多線程的優(yōu)點(diǎn),簡(jiǎn)化了高并發(fā)程序的復(fù)雜,可以有效減少編寫(xiě)、維護(hù)和觀察高吞吐量并發(fā)應(yīng)用程序的工作量。
JEP 426: 向量 API(第四次孵化)
向量(Vector) API 最初由JEP 338[13]提出,并作為孵化 API[14]集成到 JDK 16 中。第二輪孵化由JEP 414[15]提出并集成到 JDK 17 中。第三輪孵化由JEP 417[16]提出并集成到 JDK 18 中。
向量計(jì)算由對(duì)向量的一系列操作組成。向量 API 用來(lái)表達(dá)向量計(jì)算,該計(jì)算可以在運(yùn)行時(shí)可靠地編譯為支持的 CPU 架構(gòu)上的最佳向量指令,從而實(shí)現(xiàn)優(yōu)于等效標(biāo)量計(jì)算的性能。
向量 API 的目標(biāo)是為用戶(hù)提供簡(jiǎn)潔易用且與平臺(tái)無(wú)關(guān)的表達(dá)范圍廣泛的向量計(jì)算。
這是對(duì)數(shù)組元素的簡(jiǎn)單標(biāo)量計(jì)算:

這是使用 Vector API 進(jìn)行的等效向量計(jì)算:

JEP 428: 結(jié)構(gòu)化并發(fā)(孵化)
JDK 19 引入了結(jié)構(gòu)化并發(fā),一種多線程編程方法,目的是為了通過(guò)結(jié)構(gòu)化并發(fā) API 來(lái)簡(jiǎn)化多線程編程,并不是為了取代java.util.concurrent,目前處于孵化器階段。
結(jié)構(gòu)化并發(fā)將不同線程中運(yùn)行的多個(gè)任務(wù)視為單個(gè)工作單元,從而簡(jiǎn)化錯(cuò)誤處理、提高可靠性并增強(qiáng)可觀察性。也就是說(shuō),結(jié)構(gòu)化并發(fā)保留了單線程代碼的可讀性、可維護(hù)性和可觀察性。
結(jié)構(gòu)化并發(fā)的基本 API 是`StructuredTaskScope`[17]。StructuredTaskScope 支持將任務(wù)拆分為多個(gè)并發(fā)子任務(wù),在它們自己的線程中執(zhí)行,并且子任務(wù)必須在主任務(wù)繼續(xù)之前完成。
StructuredTaskScope 的基本用法如下:

結(jié)構(gòu)化并發(fā)非常適合虛擬線程,虛擬線程是 JDK 實(shí)現(xiàn)的輕量級(jí)線程。許多虛擬線程共享同一個(gè)操作系統(tǒng)線程,從而允許非常多的虛擬線程。
參考資料
[1]JEP 405: Record Patterns(記錄模式): https://openjdk.org/jeps/405
[2]JEP 422: Linux/RISC-V Port: https://openjdk.org/jeps/422
[3]JEP 424: Foreign Function & Memory API(外部函數(shù)和內(nèi)存 API): https://openjdk.org/jeps/424
[4]JEP 425: Virtual Threads(虛擬線程): https://openjdk.org/jeps/425
[5]JEP 426: Vector(向量)API: https://openjdk.java.net/jeps/426
[6]JEP 427: Pattern Matching for switch(switch 模式匹配): https://openjdk.java.net/jeps/427
[7]JEP 428: Structured Concurrency(結(jié)構(gòu)化并發(fā)): https://openjdk.org/jeps/428
[8]sun.misc.Unsafe: https://hg.openjdk.java.net/jdk/jdk/file/tip/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java
Guide to JNI (Java Native Interface): https://www.baeldung.com/jni
[10]JNA: https://github.com/java-native-access/jna
[11]JNR: https://github.com/jnr/jnr-ffi
[12]JavaCPP: https://github.com/bytedeco/javacpp
[13]JEP 338: https://openjdk.java.net/jeps/338
[14]孵化 API: http://openjdk.java.net/jeps/11
[15]JEP 414: https://openjdk.java.net/jeps/414
[16]JEP 417: https://openjdk.java.net/jeps/417
[17]StructuredTaskScope: https://download.java.net/java/early_access/loom/docs/api/jdk.incubator.concurrent/jdk/incubator/concurrent/StructuredTaskScope.html
··········? END? ··············
?? 專(zhuān)屬專(zhuān)欄/一對(duì)一提問(wèn)/簡(jiǎn)歷修改/學(xué)習(xí)打卡/讀書(shū)活動(dòng),歡迎加入? JavaGuide 知識(shí)星球 (文末可領(lǐng)取優(yōu)惠券)。
推薦閱讀?:
- 曾經(jīng)真是網(wǎng)癮少年
- 害,畢業(yè)三年了!
- 一個(gè)普通程序員的周末
- 做公眾號(hào)這一年的經(jīng)歷和一件“大事”
- 簡(jiǎn)單聊聊我的 Java 后端開(kāi)發(fā)求職之路
?? 如果本文對(duì)你有幫助的話,歡迎?點(diǎn)贊&在看&分享?,這對(duì)我繼續(xù)分享&創(chuàng)作優(yōu)質(zhì)文章非常重要。非常感謝!
