屬于Java的協(xié)程終于來了!
點擊上方“碼農(nóng)突圍”,馬上關注 這里是碼農(nóng)充電第一站,回復“666”,獲取一份專屬大禮包 真愛,請設置“星標”或點個“在看”

來源:OSC開源社區(qū)(ID:oschina2013)
關于虛擬線程 更高的吞吐量 如何啟用虛擬線程?
OpenJDK 的 JEP 425 :虛擬線程(預覽版)功能提案顯示:Java 平臺將引入虛擬線程特性(期待已久的協(xié)程)。虛擬線程是輕量級線程,可顯著地減少編寫、維護和觀察高吞吐量并發(fā)應用程序的工作量。
Java 開發(fā)人員一直依賴線程作為并發(fā)服務器應用程序的構(gòu)建塊,每個方法中的語句都在一個線程內(nèi)執(zhí)行,每個線程提供一個堆棧來存儲局部變量和協(xié)調(diào)方法調(diào)用,以及報錯時的上下文捕獲。線程是 Java 的并發(fā)單元,也是 Java 工具的核心基礎:調(diào)試器逐步執(zhí)行線程方法中的語句,分析器則可視化多個線程的行為。
目前,JDK 將其平臺線程實現(xiàn)為操作系統(tǒng) (OS) 線程的包裝器,JDK 中每個實例都是一個平臺線程,平臺線程在底層操作系統(tǒng)線程上運行 Java 代碼 ,并在代碼的整個生命周期內(nèi)捕獲 OS 線程。平臺線程數(shù)受限于 OS 線程數(shù),而 OS 線程的成本很高,不能占用太多。因此,目前 JDK 的這種線程實現(xiàn)方法限制了其應用程序的吞吐量,使吞吐量遠低于硬件支持的水平。

關于虛擬線程
虛擬線程java.lang.Thread是在底層操作系統(tǒng)線程(OS 線程)上運行 Java 代碼,但在代碼的整個生命周期內(nèi)不捕獲 OS 線程的實例。這意味著許多虛擬線程可以在同一個 OS 線程上運行 Java 代碼,從而有效地共享它。
虛擬線程是由 JDK 而不是操作系統(tǒng)提供的線程的輕量級實現(xiàn),也是用戶模式線程 的一種形式。用戶模式線程在 Java 的早期版本中被稱為“綠色線程”,當時操作系統(tǒng)線程的概念還不夠成熟和普及, Java 的所有綠色線程都共享一個 OS 線程(M:1 調(diào)度),隨著線程概念的發(fā)展,綠色線程最終被現(xiàn)在的平臺線程超越,實現(xiàn)為 OS 線程的包裝器(1:1 調(diào)度),而最新引入的虛擬線程采用 M:N 調(diào)度,其中大量 (M) 虛擬線程被調(diào)度為在較少數(shù)量 (N) 的 OS 線程上運行。
更高的吞吐量
開發(fā)者可以選擇使用虛擬線程還是平臺線程,但虛擬線程在高吞吐量的服務器應用程序中表現(xiàn)更好。比如下面這段休眠一秒鐘的代碼就創(chuàng)建了大量的虛擬線程,程序首先獲得一個 ExecutorService,它為每個提交的任務創(chuàng)建一個新的虛擬線程,然后提交 10000 個任務并等待所有任務完成:
try?(var?executor?=?Executors.newVirtualThreadPerTaskExecutor())?{
????IntStream.range(0,?10_000).forEach(i?->?{
????????executor.submit(()?->?{
????????????Thread.sleep(Duration.ofSeconds(1));
????????????return?i;
????????});
????});
}??//?executor.close()?is?called?implicitly,?and?waits
現(xiàn)代硬件可以很容易地支持 10000 個虛擬線程同時運行這樣的代碼。如果該程序使用為每個任務都創(chuàng)建一個新平臺線程的 ExecutorService,例如 Executors.newCachedThreadPool() , 那么它將嘗試創(chuàng)建 10000 個平臺線程,也就意味著 10000 個 OS 線程,那么這個程序在大多數(shù)操作系統(tǒng)上都會崩潰。又或者這個程序使用從池中獲取平臺線程的 ExecutorService,如 Executors.newFixedThreadPool(200),也好不到哪去。ExecutorService 將創(chuàng)建 200 個平臺線程供這 10000 個任務共享,任務將按順序運行而不是同時運行,程序需要很長時間才能跑完。
對于上述程序來說,具有 200 個平臺線程的池只能實現(xiàn)每秒 200 個任務的吞吐量,而虛擬線程可以實現(xiàn)大約每秒 10000 個任務的吞吐量(在充分預熱之后)。此外,如果將示例程序中的 10000 更改為 1,000,000 ,則程序?qū)⑻峤?1,000,000 個任務,創(chuàng)建 1,000,000 個并發(fā)運行的虛擬線程,并且(在充分預熱后)達到大約 1,000,000 個任務/秒的吞吐量。
總而言之,虛擬線程不是更快的線程 —— 它們運行代碼的速度并不比平臺線程快。它們的存在是為了提供規(guī)模(更高的吞吐量),而不是速度(更低的延遲)。
如何啟用虛擬線程?
目前虛擬線程在其他多線程語言中被廣泛使用(例如 Go 中的協(xié)程 和 Erlang 中的進程,在 C++ 中也是一個穩(wěn)定特性),但在 Java 中還是一個預覽 API,默認禁用。如要在 JDK XX 上嘗試該功能,則必須通過以下方法啟用預覽 API:
使用 javac --release XX --enable-preview Main.java 編譯程序,并使用 java --enable-preview Main 運行 使用源代碼啟動器時,使用 java --release XX --enable-preview Main.java 運行程序 使用 jshell 時,用 jshell --enable-preview 啟動
有關虛擬線程的更多信息可在 OpenJDK 的 JDK Issue-8277131 中查看,目前該提案于 2021/11/15 創(chuàng)立,目前還處于 JEP 流程的第一階段,距離穩(wěn)定版本還需要一段時間。
(完)
碼農(nóng)突圍資料鏈接
1、臥槽!字節(jié)跳動《算法中文手冊》火了,完整版 PDF 開放下載!
2、計算機基礎知識總結(jié)與操作系統(tǒng) PDF 下載
3、艾瑪,終于來了!《LeetCode Java版題解》.PDF
4、Github 10K+,《LeetCode刷題C/C++版答案》出爐.PDF歡迎添加魚哥個人微信:smartfish2020,進粉絲群或圍觀朋友圈
