」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 探索 JVM 虛擬執行緒機制中的固定

探索 JVM 虛擬執行緒機制中的固定

發佈於2024-11-08
瀏覽:797

Java 的虚拟线程提供了传统操作系统线程的轻量级替代方案,从而实现了高效的并发管理。但了解他们的行为对于获得最佳表现至关重要。这篇博文深入探讨了固定(一种可能影响虚拟线程执行的场景),并探讨了监控和解决该问题的技术。

虚拟线程:一种轻量级并发方法

Java 的虚拟线程是运行在底层操作系统线程(载体线程)之上的托管实体。与创建大量操作系统线程相比,它们提供了一种更有效的处理并发的方法,因为它们产生的开销较低。 JVM动态地将虚拟线程映射到承载线程,从而更好地利用资源。

  • 由 JVM 管理:与操作系统直接管理的 OS 线程不同,虚拟线程由 Java 虚拟机 (JVM) 创建和调度。这允许在 JVM 环境中进行更细粒度的控制和优化。

  • 减少开销:与操作系统线程相比,创建和管理虚拟线程所产生的开销显着降低。这是因为 JVM 可以利用较少数量的底层操作系统线程来有效管理更大的虚拟线程池。

  • 与现有代码的兼容性:虚拟线程被设计为与现有Java代码无缝集成。它们可以与传统操作系统线程一起使用,并在 Executor 和 ExecutorService 等熟悉的结构中工作,用于管理并发。

下图展示了虚拟线程和平台线程的关系:

Exploring Pinning in JVM


固定:当虚拟线程卡住时

当虚拟线程与其承载线程绑定时,就会发生固定。这本质上意味着虚拟线程在处于固定状态时不能被抢占(切换到另一个承载线程)。以下是触发固定的常见场景:

  • 同步块和方法:在同步块或方法中执行代码会导致固定。这确保了对共享资源的独占访问,防止数据损坏问题。

代码示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

  public static void main(String[] args) throws InterruptedException {

    final Counter counter = new Counter();

    Runnable task = () -> {
      for (int i = 0; i 



在此示例中,当虚拟线程进入同步块时,它会固定到其承载线程,但这并不总是正确的。仅Java的synchronized关键字不足以导致虚拟线程中的线程固定。为了发生线程固定,同步块内必须有一个阻塞点,该阻塞点会导致虚拟线程触发暂停,并最终不允许从其承载线程卸载。线程固定可能会导致性能下降,因为它会抵消使用轻量级/虚拟线程的好处。

每当虚拟线程遇到阻塞点时,其状态就会转换为 PARKING。这种状态转换是通过调用 VirtualThread.park() 方法来指示的:

// JDK core code
void park() {
  assert Thread.currentThread() == this;
  // complete immediately if parking permit available or interrupted
  if (getAndSetParkPermit(false) || interrupted)
    return;
  // park the thread
  setState(PARKING);
  try {
    if (!yieldContinuation()) {
      // park on the carrier thread when pinned
      parkOnCarrierThread(false, 0);
    }
  } finally {
    assert (Thread.currentThread() == this) && (state() == RUNNING);
  }
}

让我们看一个代码示例来说明这个概念:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

  public static void main(String[] args) {

    Counter counter = new Counter();

    Runnable task = () -> {
      for (int i = 0; i 



  • 本机方法/外部函数:运行本机方法或外部函数也可能导致固定。在这些操作期间,JVM 可能无法有效管理虚拟线程的状态。

使用 -Djdk.tracePinnedThreads=full 监视固定

-Djdk.tracePinnedThreads=full 标志是一个 JVM 启动参数,它提供有关虚拟线程固定的详细跟踪信息。启用后,它会记录以下事件:

  • 固定涉及的虚拟线程ID
  • 虚拟线程固定的承载线程ID
  • 堆栈跟踪指示导致固定的代码部分

仅在调试会话期间明智地使用此标志,因为它会带来性能开销。

  1. 编译我们的演示代码:

    javac Main.java
    
  2. 使用 -Djdk.tracePinnedThreads=full 标志启动编译的代码:

    java -Djdk.tracePinnedThreads=full Main
    
  3. 观察控制台中的输出,其中显示了有关虚拟线程固定的详细信息:

    Thread[#29,ForkJoinPool-1-worker-1,5,CarrierThreads]
    java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:183)
    java.base/jdk.internal.vm.Continuation.onPinned0(Continuation.java:393)
    java.base/java.lang.VirtualThread.parkNanos(VirtualThread.java:621)
    java.base/java.lang.VirtualThread.sleepNanos(VirtualThread.java:791)
    java.base/java.lang.Thread.sleep(Thread.java:507)
    Counter.increment(Main.java:38) 
    
    

使用可重入锁修复固定

固定是一种不良情况,它会影响虚拟线程的性能。可重入锁是抵消固定的有效工具。以下是如何使用可重入锁来缓解锁定情况:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

public class Main {

  public static void main(String[] args) {

    Counter counter = new Counter();

    Runnable task = () -> {
      for (int i = 0; i 



在更新的示例中,我们使用 ReentrantLock 而不是同步块。线程可以获取锁并在完成操作后立即释放它,与可能持有锁较长时间的同步块相比,可能会减少锁定的持续时间。

综上所述

Java 的虚拟线程证明了该语言的发展和功能。它们为传统操作系统线程提供了一种全新的、轻量级的替代方案,为高效的并发管理提供了一座桥梁。花时间深入挖掘并理解线程固定等关键概念可以让开发人员掌握充分利用这些轻量级线程潜力的专业知识。这些知识不仅帮助开发人员为利用即将推出的功能做好准备,还使他们能够在当前项目中更有效地解决复杂的并发控制问题。

版本聲明 本文轉載於:https://dev.to/yanev/exploring-pinning-in-jvms-virtual-thread-mechanism-5h13?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 在瀏覽器中將影片壓縮為 webm
    在瀏覽器中將影片壓縮為 webm
    ?增強您的網路影片:使用 React 將 MP4 壓縮為 WebM 工作中沒有任何有趣的事情感到無聊嗎?好吧,就在那時我決定抓緊時間修補瀏覽器 API 的當前狀態。我們可以直接透過 Web API 壓縮影片嗎?在這篇部落格中,我將向您展示如何使用現代瀏覽器功能將 MP4 影片壓縮為...
    程式設計 發佈於2024-11-08
  • 現代 PHP 中的 PHP Fiber 並發性
    現代 PHP 中的 PHP Fiber 並發性
    PHP Fibers 在 PHP 8.1 中引入,帶來了一種令人興奮的新方法來處理 PHP 中的並發和非同步程式設計。纖維可讓您在執行過程中暫停和恢復函數,使開發人員能夠更好地控制非阻塞操作,例如處理 I/O、資料庫查詢或 HTTP 請求,而無需停止整個腳本。 在本部落格中,我們將探討 PHP 纖...
    程式設計 發佈於2024-11-08
  • Laravel 的新時代:Accel 的百萬美元 A 輪融資——這就是為什麼它改變了遊戲規則!
    Laravel 的新時代:Accel 的百萬美元 A 輪融資——這就是為什麼它改變了遊戲規則!
    各位,请戴好帽子! Laravel 刚刚发布了一些激动人心的消息,震惊了开发界——由 Accel 领投的 A 轮融资 5700 万美元。作为一名热情的 Laravel 用户和企业家同事,这一公告在整个 PHP 社区引起了震动,我感到非常兴奋!那么,让我们来分析一下为什么这项投资意义重大,以及为什么 ...
    程式設計 發佈於2024-11-08
  • C++11 的 `string::c_str()` 仍然以 Null 終止嗎?
    C++11 的 `string::c_str()` 仍然以 Null 終止嗎?
    C 11 的 string::c_str() 是否消除空終止? 在 C 11 中,string::c_str 不再保證產生一個以 null 結尾的字串。 原因:在C 11 中,string::c_str 的定義與string::data 相同,而string::data 又被定義相當於*( begi...
    程式設計 發佈於2024-11-08
  • 資料分析師清單
    資料分析師清單
    SQL 清單 Excel女士清單 Power BI 清單 Tableau 清單 Python 清單 請關注此 WhatsApp 頻道以獲取更多資源
    程式設計 發佈於2024-11-08
  • 如何在 Go 中將 YAML 欄位動態解析為有限結構集?
    如何在 Go 中將 YAML 欄位動態解析為有限結構集?
    在 Go 中將 YAML 欄位動態解析為有限結構體集簡介在 Go 中將 YAML 解析為結構體非常簡單。但是,當 YAML 欄位可以表示多個可能的結構時,任務就會變得更加複雜。本文探討了使用 Go 的 YAML 套件的動態方法。 使用 YAML v2 進行動態解組對於 Yaml v2,可以使用以下方...
    程式設計 發佈於2024-11-08
  • 為什麼我的 C++ 程式碼中會出現「vtable」和「typeinfo」未定義符號錯誤?
    為什麼我的 C++ 程式碼中會出現「vtable」和「typeinfo」未定義符號錯誤?
    未定義的符號:「vtable」和「typeinfo」在提供的程式碼中,出現連結錯誤並顯示下列訊息: Undefined symbols: "vtable for Obstacle", referenced from: Obstacle::Obstacle()in ...
    程式設計 發佈於2024-11-08
  • 如何在 Python 中執行指數和對數曲線擬合?
    如何在 Python 中執行指數和對數曲線擬合?
    曲線擬合:Python 中的指數和對數方法雖然Python 中可以使用polyfit() 輕鬆進行多項式曲線擬合,但本指南探討了指數和對數曲線的方法擬合。 對數擬合擬合 y 形式的直線= A B log x,只需執行 y 對 log x 的多項式擬合。 import numpy as np x = ...
    程式設計 發佈於2024-11-08
  • 大批
    大批
    方法是可以在物件上呼叫的 fns 數組是對象,因此它們在 JS 中也有方法。 slice(begin):將陣列的一部分提取到新數組中,而不改變原始數組。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index ...
    程式設計 發佈於2024-11-08
  • 如何實現ES6模組的條件導入?
    如何實現ES6模組的條件導入?
    ES6模組的條件導入在ES6中,'import'和'export'關鍵字只能出現在模組的頂層模組。這可以防止條件導入,這是許多應用程式中的常見要求。這個問題探討了這個問題的解決方案。 最初,使用者嘗試使用條件語句匯入模組,但這導致了語法錯誤。然後,使用者使用 Syst...
    程式設計 發佈於2024-11-08
  • 如何在 Node.js 中使用 Promises 非同步處理 MySQL 回傳值?
    如何在 Node.js 中使用 Promises 非同步處理 MySQL 回傳值?
    在Node.js 中利用Promise 處理MySQL 回傳值從Python 過渡到Node.js,Node.js 的非同步特性使得Node.js 的非同步特性變得更加重要。 Node.js 可能會帶來挑戰。考慮一個場景,您需要從 MySQL 函數傳回一個值,例如 getLastRecord(nam...
    程式設計 發佈於2024-11-08
  • 我們應該在 C++ 函數原型中使用異常說明符嗎?
    我們應該在 C++ 函數原型中使用異常說明符嗎?
    C 中的異常:我們應該在函數原型中指定它們嗎? 在 C 中,例外說明符允許函數宣告它們是否可以拋出例外。然而,由於對其有效性和後果的擔憂,它們的使用受到了質疑。 反對使用異常說明符的原因:執行不力: 編譯器並未嚴格強制執行異常說明符,因此違反它們可能不會導致錯誤。這會破壞它們的可靠性。 程式終止:違...
    程式設計 發佈於2024-11-08
  • Python 的 If 語句中何時使用 and 關鍵字進行邏輯連結?
    Python 的 If 語句中何時使用 and 關鍵字進行邏輯連結?
    Python If 語句中的邏輯 AND在 Python 中使用 if 語句時,必須使用正確的邏輯運算子來計算多個條件。邏輯與運算子在許多程式語言中以 && 表示,它評估兩個運算元的真實性,並且僅當兩個運算元都為 true 時才傳回 True。 但是,在 Python 的 if 語句中,&& 不被辨...
    程式設計 發佈於2024-11-08
  • 什麼是 Redux,我們要如何使用它?
    什麼是 Redux,我們要如何使用它?
    What is Redux, and how do we use it? Redux is like a helpful tool for managing the state of JavaScript programs. It helps keep everything organized an...
    程式設計 發佈於2024-11-08
  • 唯一索引可以刪除具有現有重複項的表中的重複項嗎?
    唯一索引可以刪除具有現有重複項的表中的重複項嗎?
    通過唯一索引去重通過唯一索引去重為了防止重複資料插入,錯誤地為字段A、B創建了普通索引,C、D ,導致2000萬筆記錄的表中存在重複記錄。問題出現了:為這些欄位新增唯一索引會在不影響現有欄位的情況下刪除重複項嗎? 更正索引並處理重複項添加唯一索引不帶 IGNORE 修飾符的 ALTER TABLE ...
    程式設計 發佈於2024-11-08

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3