<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java協(xié)程編程之Loom項目嘗鮮

          共 5536字,需瀏覽 12分鐘

           ·

          2021-08-22 03:26

          前提

          之前很長一段時間關(guān)注JDK協(xié)程庫的開發(fā)進度,但是前一段時間比較忙很少去查看OpenJDK官網(wǎng)的內(nèi)容。Java協(xié)程項目Loom(因為項目還在開發(fā)階段,OpenJDK給出的官網(wǎng)https://openjdk.java.net/projects/loom中只有少量Loom項目相關(guān)的信息)已經(jīng)在2018年之前立項,目前已經(jīng)發(fā)布過基于JDK17編譯和JDK18編譯等早期版本,筆者在下載Loom早期版本的時候只找到JDK18編譯的版本:

          c97101baa44fb8235be447f125b274ac.webp
          ?

          下載入口在:https://jdk.java.net/loom

          ?

          由于該JDK版本過高,目前可以使用主流IDE導入Loom-JDK-18+9進行代碼高亮和語法提醒,暫時找不到方法進行編譯,暫時使用該JDK執(zhí)行目錄下的的javac命令腳本進行編譯,使用java命令腳本運行。

          Loom項目簡單介紹

          ?

          Loom - Fibers, Continuations and Tail-Calls for the JVM

          ?

          Loom項目的標題已經(jīng)凸顯了引入的三大新特性:

          • Fibers:幾年前看過當時的Loom項目的測試代碼就是使用Fiber這個API(現(xiàn)在這個API已經(jīng)被移除),意為輕量級線程,即協(xié)程,又稱為輕量級用戶線程,很神奇的是在目前的JDK中實際上稱為Virtual Thread「虛擬線程」
          • Continuations:直譯為"連續(xù)",實現(xiàn)上有點像閉包,參考不少資料,尚未準確理解其具體含義,感覺可以"粗暴"解讀為"程序接下來要執(zhí)行什么"或者"下一個要執(zhí)行的代碼塊"
          • Tail-Calls:尾調(diào)用VM級別支持

          三個新特性不詳細展開,目前只是EA版本,還存在修改的可能性,所以也沒必要詳細展開。

          Virtual Thread使用

          當前版本Loom項目中協(xié)程使用并沒有引入一個新的公開的虛擬線程VirtualThread類,雖然真的存在VirtualThread,但這個類使用default修飾符,隱藏在java.lang包中,并且VirtualThreadThread的子類。協(xié)程的創(chuàng)建API位于Thread類中:

          d0206e378d52973728fc58651d45fd1c.webp

          使用此API創(chuàng)建協(xié)程如下:

          public?static?void?main(String[]?args)?{
          ????Thread?fiber?=?Thread.startVirtualThread(()?->?System.out.println("Hello?Fiber"));
          }

          從當前的源碼可知:

          • VirtualThread會通過Thread.currentThread()獲取父線程的調(diào)度器,如果在main方法運行,那么上面代碼中的協(xié)程實例的父線程就是main線程
          • 默認的調(diào)度器為系統(tǒng)創(chuàng)建的ForkJoinPool實例(VirtualThread.DEFAULT_SCHEDULER),輸入的Runnable實例會被封裝為RunContinuation,最終由調(diào)度器執(zhí)行
          • 對于timed unpark(正在阻塞,等待喚醒)的協(xié)程,使用系統(tǒng)創(chuàng)建的ScheduledExecutorService實例進行喚醒
          • 這個靜態(tài)工廠方法創(chuàng)建完協(xié)程馬上運行,返回的是協(xié)程實例

          如果按照上面的Thread.startVirtualThread()方法去創(chuàng)建協(xié)程,顯然無法定義協(xié)程的名稱等屬性。Loom項目為Thread類引入了建造者模式,比較合理地解決了這個問題:

          //?創(chuàng)建平臺線程建造器,對應(yīng)于Thread實例
          public?static?Builder.OfPlatform?ofPlatform()?{
          ????return?new?ThreadBuilders.PlatformThreadBuilder();
          }

          //?創(chuàng)建虛擬線程建造器,對應(yīng)于VirtualThread
          public?static?Builder.OfVirtual?ofVirtual()?{
          ????return?new?ThreadBuilders.VirtualThreadBuilder();
          }

          簡單說就是:

          • ofPlatform()方法用于構(gòu)建Thread實例,這里的Platform Thread(平臺線程)其實就是JDK1.0引入的線程實例,普通的用戶線程
          • ofVirtual()方法用于構(gòu)建VirtualThread實例,也就是構(gòu)建協(xié)程實例

          這兩個建造器實例的所有Setter方法鏈展開如下:

          public?static?void?main(String[]?args)?{
          ????Thread.Builder.OfPlatform?platformThreadBuilder?=?Thread.ofPlatform()
          ????????????//?是否守護線程
          ????????????.daemon(true)
          ????????????//?線程組
          ????????????.group(Thread.currentThread().getThreadGroup())
          ????????????//?線程名稱
          ????????????.name("thread-1")
          ????????????//?線程名稱前綴?+?起始自增數(shù)字?=>?prefix?+?start,下一個創(chuàng)建的線程名稱就是prefix?+?(start?+?1)
          ????????????//?start?>?0的情況下會覆蓋name屬性配置
          ????????????.name("thread-",?1L)
          ????????????//?是否啟用ThreadLocal
          ????????????.allowSetThreadLocals(false)
          ????????????//?是否啟用InheritableThreadLocal
          ????????????.inheritInheritableThreadLocals(false)
          ????????????//?設(shè)置優(yōu)先級
          ????????????.priority(100)
          ????????????//?設(shè)置線程棧深度
          ????????????.stackSize(10)
          ????????????//?設(shè)置未捕獲異常處理器
          ????????????.uncaughtExceptionHandler(new?Thread.UncaughtExceptionHandler()?{
          ????????????????@Override
          ????????????????public?void?uncaughtException(Thread?t,?Throwable?e)?{

          ????????????????}
          ????????????});
          ????//?thread-1
          ????Thread?firstThread?=?platformThreadBuilder.unstarted(()?->?System.out.println("Hello?Platform?Thread?First"));
          ????//?thread-2
          ????Thread?secondThread?=?platformThreadBuilder.unstarted(()?->?System.out.println("Hello?Platform?Thread?Second"));
          ????Thread.Builder.OfVirtual?virtualThreadBuilder?=?Thread.ofVirtual()
          ????????????//?協(xié)程名稱
          ????????????.name("fiber-1")
          ????????????//?協(xié)程名稱前綴?+?起始自增數(shù)字?=>?prefix?+?start,下一個創(chuàng)建的協(xié)程名稱就是prefix?+?(start?+?1)
          ????????????//?start?>?0的情況下會覆蓋name屬性配置
          ????????????.name("fiber-",?1L)
          ????????????//?是否啟用ThreadLocal
          ????????????.allowSetThreadLocals(false)
          ????????????//?是否啟用InheritableThreadLocal
          ????????????.inheritInheritableThreadLocals(false)
          ????????????//?設(shè)置調(diào)度器,Executor實例,也就是調(diào)度器是一個線程池,設(shè)置為NULL會使用VirtualThread.DEFAULT_SCHEDULER
          ????????????.scheduler(null)
          ????????????//?設(shè)置未捕獲異常處理器
          ????????????.uncaughtExceptionHandler(new?Thread.UncaughtExceptionHandler()?{
          ????????????????@Override
          ????????????????public?void?uncaughtException(Thread?t,?Throwable?e)?{

          ????????????????}
          ????????????});
          ????//?fiber-1
          ????Thread?firstFiber?=?virtualThreadBuilder.unstarted(()?->?System.out.println("Hello?Platform?Virtual?First"));
          ????//?fiber-2
          ????Thread?secondFiber?=?virtualThreadBuilder.unstarted(()?->?System.out.println("Hello?Platform?Virtual?Second"));
          }

          這里可以發(fā)現(xiàn)一點,就是「建造器是可以復用的」。如果想用建造器創(chuàng)建同一批參數(shù)設(shè)置相同的線程或者協(xié)程,可以設(shè)置name(String prefix, long start)方法,定義線程或者協(xié)程的名稱前綴和一個大于等于0的數(shù)字,反復調(diào)用Builder#unstarted(Runnable task)方法就能批量創(chuàng)建線程或者協(xié)程,名稱就設(shè)置為prefix + start、prefix + (start + 1)、prefix + (start + 2)以此類推。協(xié)程創(chuàng)建基本就是這么簡單,運行的話直接調(diào)用start()方法:

          public?class?FiberSample2?{

          ????public?static?void?main(String[]?args)?throws?Exception?{
          ????????Thread.ofVirtual()
          ????????????????.name("fiber-1")
          ????????????????.allowSetThreadLocals(false)
          ????????????????.inheritInheritableThreadLocals(false)
          ????????????????.unstarted(()?->?{
          ????????????????????Thread?fiber?=?Thread.currentThread();
          ????????????????????System.out.printf("[%s,daemon:%s,virtual:%s]?-?Hello?World\n",?fiber.getName(),
          ????????????????????????????fiber.isDaemon(),?fiber.isVirtual());
          ????????????????}).start();
          ????????//?主線程休眠
          ????????Thread.sleep(Long.MAX_VALUE);
          ????}
          }

          目前無法在主流IDE編譯上面的類,所以只能使用該JDK目錄下的工具編譯和運行,具體如下:

          #?執(zhí)行?-?當前目錄I:\J-Projects\framework-source-code\fiber-sample\src\main\java
          (1)編譯:I:\Environment\Java\jdk-18-loom\bin\javac.exe I:\J-Projects\framework-source-code\fiber-sample\src\main\java\cn\throwx\fiber\sample\FiberSample2.java
          (2)執(zhí)行main方法:I:\Environment\Java\jdk-18-loom\bin\java.exe cn.throwx.fiber.sample.FiberSample2
          77a49c7dff8126e50c2d1cec2d186ee7.webp

          這里也看出了一點,所有的協(xié)程實例的daemon標識默認為true且不能修改。

          小結(jié)

          如果用嘗鮮的角度去使用Loom項目,可以提前窺探JVM開發(fā)者們是如何基于協(xié)程這個重大特性進行開發(fā)的,這對于提高學習JDK內(nèi)核代碼的興趣有不少幫助。從目前來看,對于協(xié)程的實現(xiàn)Loom項目距離RELEASE版本估計還有不少功能需要完善,包括新增API的穩(wěn)定性,以及協(xié)程是否能夠移植到原有的JUC類庫中使用(當前的Loom-JDK-18+9沒有對原來的線程池等類庫進行修改)等問題需要解決,所以在保持關(guān)注的過程中靜心等待吧。

          (本文完 e-a-20210818 c-2-d)

          瀏覽 74
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  狠狠躁日日躁XXXXAAAA | 黃色A片一级一级一级久别的草原 | 精品成人无码麻豆 | 日韩中文字幕网 | 91精品秘 一区二区三区 |