<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      潦草白紙

      監(jiān)控Java虛擬線程

      監(jiān)控 Java 虛擬線程

      開發(fā)便利性 與 運行高效性

      開發(fā)便利性 與 運行高效性

      簡介

      在我之前的文章中,我們已經(jīng)討論了什么是虛擬線程(VTs),他們與物理線程(PTs)之間的區(qū)別,以及如何使用 Java 虛擬線程(JVTs)來創(chuàng)建反應(yīng)式微服務(wù)(Helidon 4)。

      簡單來說,VTs(虛擬線程)引入了一種新的并發(fā)模型。與使用可能會被阻塞的PTs(物理線程)不同,我們僅使用少量的VTs,且?guī)缀醪粫蛔枞W枞粋€PT是昂貴的,可能會限制我們的擴展能力。另一方面,VTs即使遭遇阻塞,亦不會增加額外成本。

      有了VTs(虛擬線程),我們可以以平鋪直敘的方式直接編碼,而不必使用復(fù)雜的響應(yīng)式編程,與此同時仍然享受代碼高效運行好處。換句話說,我們不再需要在“開發(fā)便利性 與 運行高效性”之間做出兩難選擇。

      為了進(jìn)一步探討這個主題,我邀請您觀看我在2023年EclipseCon上關(guān)于Java Loom的開發(fā)者視角的演講

      虛擬線程監(jiān)控的具體細(xì)節(jié)

      有一個值得考慮的重要問題被VTs(虛擬線程)引入了,那就是監(jiān)控:我們?nèi)绾未_保我們的應(yīng)用程序以最佳方式使用虛擬線程?在涉及虛擬線程時,我們到底需要監(jiān)控哪些具體內(nèi)容?

      為了回答這些問題,我們需要理解VTs(虛擬線程)在底層是如何工作的,特別是如何管理阻塞操作:

      管理阻塞

      在JVM 內(nèi)部一切都圍繞著一個名為Continuation的類展開。Continuation類是Java的內(nèi)部一個類,作為開發(fā)者,我們不必直接與Continuation交互。像是Java內(nèi)部的NIO庫和垃圾回收器一樣被很好的封裝。

      Continuation類暴露了兩個主要方法:

      1. run 方法用于啟動(或重啟)一個任務(wù)
      2. yield 方法用于暫停正在運行的任務(wù)。

      在內(nèi)部,虛擬線程(VT)將其任務(wù)執(zhí)行委托給一個Continuation類的示例。

      從本質(zhì)上講,虛擬線程(VT)是一種輕量級并發(fā)構(gòu)造器,它沒有自己的執(zhí)行能力。當(dāng)它運行時,被掛載到一個物理線程(PT)上運行。更確切地說,這個物理線程(PT)是專門提供給虛擬線程(VT)執(zhí)行的ForkJoinPool。這些專門定制的物理線程(PT)又被成為載荷線程Carrier Threads(CTs)。

      虛擬線程(VT),物理線程(PT),載荷線程(CT),這么多詞匯。別迷糊,一切都會變得清晰。

      當(dāng)虛擬線程(VT)被阻塞,例如等待IO時,會調(diào)用Continuation類的yield方法,并且虛擬線程會被卸載。此時載荷線程(CT)不會被阻塞(這就是神奇之處!),載荷線程持有任務(wù)資源將會被返還,此時會執(zhí)行其他虛擬線程(VT)任務(wù)。

      當(dāng)IO讀寫完畢,Continuation的run方法將會被調(diào)用(由JVM內(nèi)部的讀取輪詢線程調(diào)度),并且該虛擬線程會被重新掛載到一個載荷線程(CT)上(并不一定仍然是之前的線程)重新繼續(xù)運行。

      為了啟用這種掛載/卸載機制,我們需要保存和恢復(fù) Java 堆棧,即任務(wù)的執(zhí)行上下文。它被保存在 Java 堆中,所有對象都存儲在那里。這意味著虛擬線程的使用會增加內(nèi)存占用,并給垃圾收集器(GC)增加壓力。作為 Java 開發(fā)人員,我們知道當(dāng) GC 開始進(jìn)行full collections時,延遲會提升、可伸縮性會變差。對于虛擬線程來說更是如此!

      顯然,使用虛擬線程加強了對內(nèi)存占用和垃圾收集器活動進(jìn)行監(jiān)控的必要性。

      我們可以通過使用以下經(jīng)典方法來監(jiān)控虛擬線程的使用:

      • Java 啟動參數(shù):-Xlog:gc 或 -XX:NativeMemoryTracking
      • Java 飛行記錄器(JFR)事件。

      跟蹤牽制線程(pinned threads)

      所以,多虧了Continuation的魔力,載荷線程(CTs)永遠(yuǎn)不會被阻塞...真是這樣嗎?實際上,它們幾乎不會阻塞。但在某些情況下,虛擬線程(VT)不能被卸載,從而阻止其關(guān)聯(lián)的載荷線程(CT)。

      當(dāng)Java堆棧地址被非Java代碼引用時會發(fā)生這種情況。當(dāng)從堆中還原時,Java地址會被重新定位,使非Java引用不再有效。

      為了防止這種錯誤發(fā)生,將載荷線程(CT)設(shè)置為“牽制”狀態(tài)。(這意味著它永遠(yuǎn)不會被卸載。)

      線程牽制

      這種情況發(fā)生在以下情況下:

      1. 調(diào)用了同步(synchronized)塊或方法
      2. 調(diào)用了本地代碼:即來自 JVM 本身的內(nèi)部代碼,或使用 JNI 或外部調(diào)用代碼的外部調(diào)用函數(shù)。

      這是一個問題嗎?這取決于…… 當(dāng)牽制線程背后的處理過程緩慢且頻繁調(diào)用時,這可能會限制性能,例如在 JDBC 驅(qū)動程序中。 另一方面,當(dāng)處理速度快或調(diào)用不頻繁時,這就不是問題了。

      這意味著我們必須跟蹤牽制線程,以識別那些可能影響性能的線程。

      我們可以利用以下方式跟蹤:

      • -Djdk.tracePinnedThreads Java 啟動選項:它能夠確定代碼中發(fā)生牽制線程的位置。
      • JFR 事件 jdk.VirtualThreadPinned:它能夠識別可能影響性能的牽制線程。此事件默認(rèn)啟用,閾值為 20 毫秒(可配置):

      例如,這種配置可以設(shè)置跟蹤牽制線程閾值為 5 毫秒:

      <event name="jdk.VirtualThreadPinned">
        <setting name="enabled">true</setting>
        <setting name="stackTrace">true</setting>
        <setting name="threshold">5 ms</setting>
      </event>
      

      在這種情況下,只有持續(xù)時間超過 5 毫秒的牽制線程才會被監(jiān)視。

      我的框架如何使用虛擬線程?

      沒有使用虛擬線程(VTs)的唯一標(biāo)準(zhǔn)方式。每個框架都根據(jù)其架構(gòu)和繼續(xù)需求進(jìn)行取舍適配。

      正如我們在之前的文章中看到的那樣,Helidon 4提出了一種激進(jìn)的方案,即業(yè)務(wù)代碼系統(tǒng)性且有條理地在虛擬線程(VTs)的上下文中運行。

      Helidon 架構(gòu)圖

      這需要注意的是,Helidon 4 在內(nèi)部利用物理線程(PTs)來滿足其連接管理需求。業(yè)務(wù)代碼是系統(tǒng)性且有條理地在虛擬線程(VTs)中運行。

      由于其架構(gòu)的原因,Quarkus 提供了一種不同的方案。按Quarkus的設(shè)計,其使用兩種類型的專門化物理線程(PTs):

      1. IO 線程,執(zhí)行 IO 和非阻塞反應(yīng)式代碼
      2. Worker 線程,執(zhí)行阻塞代碼。

      作為一種可選項,可以通過使用特性的注解,在虛擬線程(VTs)中運行阻塞代碼:

      Quarkus 架構(gòu)圖

      這是一種混合方案,允許開發(fā)者逐步遷移到虛擬線程(VTs)中。

      那么,Helidon 的激進(jìn)方法還是 Quarkus 的混合方法更好?這并沒有絕對的答案。這取決于業(yè)務(wù)背景上下文:

      1. 激進(jìn)方法的優(yōu)點在于簡單易行。然而,在處理CPU密集型任務(wù)或固定線程影響性能時,它并不是最佳選擇。
      2. 混合方法允許逐步、可控地采用虛擬線程。然而,由于導(dǎo)致IO線程和虛擬線程工作線程之間的上下文切換,它并不理想。Quarkus 架構(gòu)可能會進(jìn)化出跟優(yōu)秀的方案以更好地利用虛擬線程(VTs)。

      以上兩個示例表明,我們需要了解我們喜愛的框架如何使用虛擬線程(VTs),并監(jiān)控虛擬線程(VTs)的創(chuàng)建和刪除方式

      這可以通過啟用和跟蹤 JFR 事件來完成:jdk.VirtualThreadStartjdk.VirtualThreadEnd。這些事件默認(rèn)是禁用的,要啟用它們,必須使用特定的 JFR 配置:

      <event name="jdk.VirtualThreadStart">
        <setting name="enabled">true</setting>
        <setting name="stackTrace">true</setting>
       </event>
      <event name="jdk.VirtualThreadEnd">
        <setting name="enabled">true</setting>
      </event>
      

      并且引入對應(yīng)配置:

      java -XX:StartFlightRecording,settings=/path/to/jfr-config ...
      

      監(jiān)控 ForkJoinPool

      正如我們所知,F(xiàn)orkJoinPool 扮演了一個至關(guān)重要的角色在 Java 虛擬線程(VTs)中。如果池子太小,調(diào)度將會減慢并且降低性能。

      可以使用以下系統(tǒng)屬性配置 ForkJoinPool:

      • jdk.virtualThreadScheduler.parallelism:池大小(有多少個載荷線程(CT)),默認(rèn)為 CPU 核心數(shù)
      • jdk.virtualThreadScheduler.maxPoolSize:池的最大大小,默認(rèn)為 256。當(dāng)載荷線程(CT)被阻塞時(由于操作系統(tǒng)或 JVM 的限制),載荷線程(CT)的數(shù)量可能會暫時超過并行值設(shè)置的數(shù)量。請注意,調(diào)度程序不會通過擴大并行性來補償牽制
      • jdk.virtualThreadScheduler.minRunnable:在池中保持可運行的最小線程數(shù)。

      在大多數(shù)情況下,默認(rèn)值是合適的,不需要更改它們。

      在這個階段,我還沒有找到監(jiān)測專用于虛擬線程(VTs)的 ForkJoinPool 的方法。例如,擁有確定虛擬線程(VTs)調(diào)度延遲的指標(biāo)(虛擬線程(VTs)裝載到載荷線程(CT)上需要多長時間)并相應(yīng)地調(diào)整配置會很有趣。

      結(jié)論

      在本文中,我們確定了使用虛擬線程(VTs)時需要監(jiān)控的主要技術(shù)要素:

      • 內(nèi)存堆大小和 GC 活動:這些是需要用虛擬線程(VTs)加強的經(jīng)典監(jiān)控元素
      • 牽制線程,尤其是那些可能影響性能的線程
      • 虛擬線程(VTs)的創(chuàng)建:每個框架都有自己的虛擬線程(VTs)使用策略,需要加以理解
      • ForkJoinPool 調(diào)度程序大小調(diào)整:不適當(dāng)?shù)拇笮≌{(diào)整可能導(dǎo)致性能下降,即使(據(jù)我所知)沒有真正的監(jiān)控方法,我們也可以對配置進(jìn)行一些處理總的來說,以下是我推薦的 Java 選項:
      java \
         -Djdk.tracePinnedThreads=short \
         -XX:NativeMemoryTracking=summary \
         -Xlog:gc:/path/to/gc-log \
         -XX:StartFlightRecording,settings=...,name=...,filename=...  \
         -jar /path/to/app-jar-file
      

      我們將在下一篇文章中研究使用 Helidon 和 Quarkus 的具體方法。

      參考

      Networking I/O with Virtual Threads – Under the hood

      The Ultimate Guide to Java Virtual Threads

      JEP 444: Virtual Threads

      Help Center Virtual Threads documentation

      What’s using my pod memory

      posted on 2024-02-18 18:46  潦草白紙  閱讀(499)  評論(0)    收藏  舉報

      導(dǎo)航

      主站蜘蛛池模板: 无码AV无码免费一区二区| 亚洲成色精品一二三区| 日韩区中文字幕在线观看| 国内精品自国内精品自久久 | 久久亚洲国产成人亚| 免费无码一区无码东京热| 韩国无码av片在线观看| 久久久亚洲欧洲日产国码606| 婷婷久久综合九色综合88| 90后极品粉嫩小泬20p| 青青草国产线观看| 亚洲中文字幕国产精品| 无码伊人久久大杳蕉中文无码| 午夜高清福利在线观看| 18岁日韩内射颜射午夜久久成人 | 91精品亚洲一区二区三区| 亚洲国产精品一区二区三| 亚洲一级特黄大片在线观看 | 久久综合伊人77777| 97久久精品人人做人人爽| 午夜在线观看成人av| 象州县| 99久久精品国产一区二区暴力| 亚洲免费一区二区av| 欧美人与动牲交A免费观看| 亚洲av产在线精品亚洲第一站| 99热久久这里只有精品| 欧美人与动zozo在线播放| 男女xx00上下抽搐动态图| 亚洲乱熟乱熟女一区二区| 狠狠色综合久久丁香婷婷| 狠狠亚洲色一日本高清色| 麻豆av一区二区天美传媒| 亚洲AV无码专区亚洲AV紧身裤| 贡觉县| 国精品无码一区二区三区左线| 国产成人一区二区不卡| 18禁免费无码无遮挡不卡网站 | 国精品午夜福利视频不卡| 国内少妇偷人精品免费| 国产性色av高清在线观看|