Loom會造成CPU密集型執行緒的不公平排程

banq發表於2022-05-29

Project Loom ( JEP 425 ) 可能是 Java 有史以來最受期待的新增功能之一。它對虛擬執行緒(或“綠色執行緒”)的實現保證了開發人員能夠建立高度併發的應用程式,例如具有數十萬個開啟的 HTTP 連線,堅持眾所周知的執行緒每個請求的程式設計模型,而無需訴諸不太熟悉且通常更復雜的反應式方法。

經過幾年的努力,Loom最近才被合併到 OpenJDK 的主線中,並在最新的[url=https://jdk.java.net/19/]Java 19 早期訪問版本[/url]中作為預覽功能提供。即,現在是接觸虛擬執行緒並探索新功能的最佳時機。

虛擬執行緒由 JVM排程到作業系統級別的載體執行緒上。如果應用程式程式碼遇到阻塞方法,Loom 會從當前的載體上解除安裝虛擬執行緒,為其他虛擬執行緒騰出空間進行排程。
虛擬執行緒很便宜並且由 JVM 管理,也就是說,您可以擁有很多,甚至數百萬。

那麼, Loom 的排程器如何知道一個方法正在阻塞?事實證明,它沒有。
從Project Loom 的主要作者Ron Pressler那裡瞭解到,情況正好相反:JDK 中的阻塞方法已經針對 Loom 進行了調整,以便在被虛擬執行緒呼叫時釋放 OS 級別的載體執行緒:

Java 中的所有阻塞都是通過 JDK 完成的(除非您顯式呼叫本機程式碼)。我們將 JDK 中的“葉leaf”阻塞方法更改為阻塞虛擬執行緒而不是平臺執行緒。例如,在所有 java.util.concurrent 中只有一種這樣的方法:LockSupport.park

如果程式碼不是 IO-boundIO密集型,而是 CPU-bound CPU密集型,會發生什麼?即,如果虛擬執行緒中的程式碼在沒有呼叫任何 JDK 的“葉leaf”阻塞方法的情況下執行一些繁重的計算,那麼虛擬執行緒會怎樣?

假設有一組worker執行 CPU 密集型任務,因為沒有yield點。您在不同的虛擬執行緒上啟動了許多工。您希望它們都在同一時間完成。在這種情況下它們不會在同一時間完成,並且完成的時間將隨機地大不相同。

在虛擬執行緒和作業系統級執行緒的情況下,CPU密集的程式碼的行為實際上是非常不同的:
有的虛擬執行緒會一直在執行,而其他虛擬執行緒則會發生類似被堵塞的現象,等待這些虛擬執行緒執行一段時間才執行,而不是每段虛擬執行緒都能公平地輪流被執行。

當然,這種情況只在有超過CPU執行緒水平的併發全佔據CPU的情況下才會發生,不過這還是這引起了大家對公平性的擔憂,但這不是一種常見的情況,而且在這種邊緣情況下不使用虛擬執行緒是可以避免的。

在這種情況下,java開發者需要成為一定水平的專家,瞭解Loom適合哪些使用情況,哪些不適合,這大大增加了錯誤的概率。
為什麼不讓Loom在所有情況下都能很好地更容易地工作呢,就像Go語言一樣?

 

相關文章