之前很長一段時間關注<code>JDK</code>協程庫的開發進度,但是前一段時間比較忙很少去檢視<code>OpenJDK</code>官網的内容。<code>Java</code>協程項目<code>Loom</code>(因為項目還在開發階段,<code>OpenJDK</code>給出的官網<code>https://openjdk.java.net/projects/loom</code>中隻有少量<code>Loom</code>項目相關的資訊)已經在<code>2018</code>年之前立項,目前已經釋出過基于<code>JDK17</code>編譯和<code>JDK18</code>編譯等早期版本,筆者在下載下傳<code>Loom</code>早期版本的時候隻找到<code>JDK18</code>編譯的版本:

下載下傳入口在:https://jdk.java.net/loom
由于該<code>JDK</code>版本過高,目前可以使用主流<code>IDE</code>導入<code>Loom-JDK-18+9</code>進行代碼高亮和文法提醒,暫時找不到方法進行編譯,暫時使用該<code>JDK</code>執行目錄下的的<code>javac</code>指令腳本進行編譯,使用<code>java</code>指令腳本運作。
Loom - Fibers, Continuations and Tail-Calls for the JVM
<code>Loom</code>項目的标題已經凸顯了引入的三大新特性:
<code>Fibers</code>:幾年前看過當時的<code>Loom</code>項目的測試代碼就是使用<code>Fiber</code>這個<code>API</code>(現在這個<code>API</code>已經被移除),意為輕量級線程,即協程,又稱為輕量級使用者線程,很神奇的是在目前的<code>JDK</code>中實際上稱為<code>Virtual Thread</code>(虛拟線程)
<code>Continuations</code>:直譯為"連續",實作上有點像閉包,參考不少資料,尚未準确了解其具體含義,感覺可以"粗暴"解讀為"程式接下來要執行什麼"或者"下一個要執行的代碼塊"
<code>Tail-Calls</code>:尾調用<code>VM</code>級别支援
三個新特性不詳細展開,目前隻是<code>EA</code>版本,還存在修改的可能性,是以也沒必要詳細展開。
目前版本<code>Loom</code>項目中協程使用并沒有引入一個新的公開的虛拟線程<code>VirtualThread</code>類,雖然真的存在<code>VirtualThread</code>,但這個類使用<code>default</code>修飾符,隐藏在<code>java.lang</code>包中,并且<code>VirtualThread</code>是<code>Thread</code>的子類。協程的建立<code>API</code>位于<code>Thread</code>類中:
使用此<code>API</code>建立協程如下:
從目前的源碼可知:
<code>VirtualThread</code>會通過<code>Thread.currentThread()</code>擷取父線程的排程器,如果在<code>main</code>方法運作,那麼上面代碼中的協程執行個體的父線程就是<code>main</code>線程
預設的排程器為系統建立的<code>ForkJoinPool</code>執行個體(<code>VirtualThread.DEFAULT_SCHEDULER</code>),輸入的<code>Runnable</code>執行個體會被封裝為<code>RunContinuation</code>,最終由排程器執行
對于<code>timed unpark</code>(正在阻塞,等待喚醒)的協程,使用系統建立的<code>ScheduledExecutorService</code>執行個體進行喚醒
這個靜态工廠方法建立完協程馬上運作,傳回的是協程執行個體
如果按照上面的<code>Thread.startVirtualThread()</code>方法去建立協程,顯然無法定義協程的名稱等屬性。<code>Loom</code>項目為<code>Thread</code>類引入了建造者模式,比較合理地解決了這個問題:
簡單說就是:
<code>ofPlatform()</code>方法用于建構<code>Thread</code>執行個體,這裡的<code>Platform Thread</code>(平台線程)其實就是<code>JDK1.0</code>引入的線程執行個體,普通的使用者線程
<code>ofVirtual()</code>方法用于建構<code>VirtualThread</code>執行個體,也就是建構協程執行個體
這兩個建造器執行個體的所有<code>Setter</code>方法鍊展開如下:
這裡可以發現一點,就是建造器是可以複用的。如果想用建造器建立同一批參數設定相同的線程或者協程,可以設定<code>name(String prefix, long start)</code>方法,定義線程或者協程的名稱字首和一個大于等于<code>0</code>的數字,反複調用<code>Builder#unstarted(Runnable task)</code>方法就能批量建立線程或者協程,名稱就設定為<code>prefix + start</code>、<code>prefix + (start + 1)</code>、<code>prefix + (start + 2)</code>以此類推。協程建立基本就是這麼簡單,運作的話直接調用<code>start()</code>方法:
目前無法在主流<code>IDE</code>編譯上面的類,是以隻能使用該<code>JDK</code>目錄下的工具編譯和運作,具體如下:
這裡也看出了一點,所有的協程執行個體的<code>daemon</code>辨別預設為<code>true</code>且不能修改。
如果用嘗鮮的角度去使用<code>Loom</code>項目,可以提前窺探<code>JVM</code>開發者們是如何基于協程這個重大特性進行開發的,這對于提高學習<code>JDK</code>核心代碼的興趣有不少幫助。從目前來看,對于協程的實作<code>Loom</code>項目距離<code>RELEASE</code>版本估計還有不少功能需要完善,包括新增<code>API</code>的穩定性,以及協程是否能夠移植到原有的<code>JUC</code>類庫中使用(目前的<code>Loom-JDK-18+9</code>沒有對原來的線程池等類庫進行修改)等問題需要解決,是以在保持關注的過程中靜心等待吧。
(e-a-20210818 c-2-d)