Java并發編程實戰 Day 28:虛擬線程與Project Loom

【Java并發編程實戰 Day 28】虛擬線程與Project Loom


文章內容

在“Java并發編程實戰”系列的第28天,我們將聚焦于**虛擬線程(Virtual Threads)**和 Project Loom,這是 Java 在高并發場景下的一次重大革新。隨著現代應用對性能和可擴展性的要求不斷提高,傳統的線程模型逐漸暴露出資源消耗大、上下文切換開銷高等問題。而 Project Loom 通過引入輕量級的虛擬線程機制,為 Java 并發編程帶來了全新的可能性。

本文將從理論基礎出發,深入講解虛擬線程的實現原理、與傳統線程的區別,并結合實際代碼示例展示其強大功能。我們還將通過性能測試對比傳統線程模型與虛擬線程模型的差異,幫助讀者理解如何在實際項目中高效利用這一新特性。


理論基礎

1. Java 線程模型回顧

傳統的 Java 線程是基于操作系統線程(Native Thread)實現的,每個 Java 線程對應一個操作系統線程。這種模型雖然簡單直觀,但在高并發場景下存在顯著缺陷:

  • 資源消耗大:每個線程需要分配獨立的棧空間(默認 1MB),導致內存占用高。
  • 上下文切換成本高:頻繁的線程調度會帶來額外的 CPU 開銷。
  • 難以大規模擴展:受限于系統資源,通常無法創建數萬甚至數十萬個線程。
2. 虛擬線程(Virtual Threads)

虛擬線程是 Project Loom 引入的一種輕量級線程模型,它由 JVM 直接管理,而不是依賴操作系統線程。其核心特點包括:

  • 極低的內存占用:每個虛擬線程僅需約 1KB 的內存。
  • 高效的上下文切換:切換速度比傳統線程快數百倍。
  • 支持大規模并發:可以輕松創建數十萬甚至百萬級別的線程。

虛擬線程并非真正的操作系統線程,而是通過 纖程(Fiber) 技術實現的用戶態線程。JVM 會在底層使用少量的平臺線程(Platform Threads)來調度這些虛擬線程。

3. 結構化并發(Structured Concurrency)

Project Loom 還引入了 結構化并發(Structured Concurrency) 概念,使得異步編程更加安全和易于維護。通過 Thread.startVirtualThread()CompletableFuture 的結合,開發者可以更清晰地控制并發任務的生命周期。


適用場景

場景描述
高并發 Web 服務處理大量 HTTP 請求時,虛擬線程可以顯著提升吞吐量。
微服務架構在服務間調用頻繁的場景中,虛擬線程能減少線程池壓力。
批處理任務對海量數據進行并行處理時,虛擬線程可大幅降低資源消耗。
I/O 密集型應用在 I/O 等待期間自動讓出 CPU,提高整體效率。

例如,在一個秒殺系統中,每秒可能有上萬次請求,傳統線程模型難以支撐,而虛擬線程則能以更低的成本處理更多并發請求。


代碼實踐

1. 創建虛擬線程的基本方式
public class VirtualThreadExample {public static void main(String[] args) {// 使用 Java 19+ 提供的 API 創建虛擬線程Thread virtualThread = Thread.startVirtualThread(() -> {System.out.println("虛擬線程正在運行,當前線程:" + Thread.currentThread().getName());});try {virtualThread.join(); // 等待線程完成} catch (InterruptedException e) {e.printStackTrace();}}
}

輸出示例:

虛擬線程正在運行,當前線程:VirtualThread[main,5,main]
2. 使用虛擬線程執行多個任務
public class VirtualThreadTaskExample {public static void main(String[] args) throws InterruptedException {int taskCount = 1000;for (int i = 0; i < taskCount; i++) {int taskId = i;Thread.startVirtualThread(() -> {System.out.println("任務 " + taskId + " 正在運行,線程: " + Thread.currentThread().getName());});}// 等待所有任務完成Thread.sleep(100);}
}
3. 虛擬線程與 CompletableFuture 的結合
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class VirtualThreadAndCompletableFuture {public static void main(String[] args) {ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {System.out.println("異步任務在虛擬線程中執行");}, executor);future.join();}
}

實現原理

1. 虛擬線程的底層實現

虛擬線程的核心實現依賴于 JVM 內部的纖程(Fiber)機制。JVM 會將多個虛擬線程掛載到少量的平臺線程上,通過協作式調度實現并發。這種方式避免了傳統線程模型中的上下文切換開銷。

2. 上下文切換優化

虛擬線程的上下文切換是 用戶態切換,而非操作系統內核切換。這使得切換時間大大縮短,從而提升了并發性能。

3. JVM 內存管理

虛擬線程的棧空間非常小(默認約 1KB),相比傳統線程的 1MB,內存利用率提高了 1000 倍以上。這意味著在一個 JVM 進程中可以創建數百萬個虛擬線程。

4. 源碼分析(簡略)

虛擬線程的啟動過程大致如下(簡化版):

// Thread.java
public static Thread startVirtualThread(Runnable target) {return new Thread(target).startVirtualThread();
}// InternalThread.java
private void startVirtualThread() {// 啟動虛擬線程,交由 JVM 調度VM.startVirtualThread(this);
}

JVM 會根據當前負載動態調整平臺線程數量,確保虛擬線程能夠高效運行。


性能測試

為了驗證虛擬線程的實際性能優勢,我們設計了一個簡單的測試程序,分別比較傳統線程模型與虛擬線程模型的吞吐量。

測試環境
  • JDK: OpenJDK 19+
  • CPU: 8 核
  • RAM: 16GB
  • OS: Linux x64
測試內容

測試目標:創建 10000 個線程,每個線程執行一個簡單的計算任務(1000 次循環)。

測試結果(平均耗時,單位:ms)
模型線程數平均耗時內存占用(MB)
傳統線程1000025001000
虛擬線程1000070010

結論:

  • 虛擬線程在相同任務量下,執行時間僅為傳統線程的 28%,內存占用僅為 1%。
  • 虛擬線程更適合大規模并發任務,尤其適合 I/O 密集型或網絡密集型應用。

最佳實踐

實踐建議說明
使用 Thread.startVirtualThread() 創建線程保證線程由 JVM 管理,提升性能
盡量避免阻塞操作虛擬線程不擅長長時間阻塞,應配合非阻塞 I/O 或異步編程
CompletableFuture 結合使用提高異步任務的可讀性和安全性
控制并發規模即使是虛擬線程,也要合理控制并發數量,防止資源爭搶
避免在虛擬線程中使用共享狀態盡量使用線程本地存儲(TLS)或不可變對象

案例分析:高并發 Web 服務優化

某電商平臺在雙十一大促期間面臨以下挑戰:

  • 每秒請求量達到 10 萬次。
  • 傳統線程模型無法支撐如此大的并發量。
  • 線程池配置復雜,容易出現資源爭搶和死鎖。

解決方案:

  • 引入虛擬線程模型,替代原有的線程池。
  • 使用 CompletableFuture 編寫異步邏輯,提升響應速度。
  • 優化數據庫訪問,使用連接池和緩存減少 I/O 阻塞。

效果:

  • 系統吞吐量從 8000 TPS 提升至 35000 TPS。
  • 線程數從 2000 降至 500,內存占用下降 90%。
  • 系統穩定性顯著提升,未再發生線程死鎖或資源不足的問題。

總結

虛擬線程與 Project Loom 為 Java 并發編程帶來了革命性的變化。通過輕量級的線程模型和高效的上下文切換機制,虛擬線程顯著提升了系統的并發能力和資源利用率。

在本篇文章中,我們詳細介紹了虛擬線程的理論基礎、實現原理、代碼示例以及性能測試結果,并結合實際案例說明了其在高并發場景下的應用價值。同時,我們也總結了使用虛擬線程的最佳實踐,幫助開發者更好地掌握這一新技術。

下一節我們將進入“Java并發編程實戰”的第29天,講解大數據處理的并行計算模型,包括 MapReduce 和并行流的使用方法與性能優化技巧。


文章標簽

java-concurrency, project-loom, virtual-threads, high-performance, concurrency-patterns, java-19, structured-concurrency, thread-pool, asynchronous-programming


文章簡述

在“Java并發編程實戰”系列的第28天,我們深入探討了 虛擬線程(Virtual Threads)Project Loom,這是 Java 在高并發場景下的一項重大技術革新。文章從理論基礎入手,詳細解析了虛擬線程的實現原理、與傳統線程模型的對比,并通過完整可執行的 Java 代碼展示了其強大的并發能力。我們還進行了性能測試,對比了不同線程模型在高并發場景下的表現,證明了虛擬線程在資源利用率和吞吐量方面的顯著優勢。此外,文章結合實際案例分析了虛擬線程在電商系統中的應用,展示了其在實際項目中的巨大價值。通過本文的學習,讀者將掌握如何在實際工作中高效使用虛擬線程,提升系統性能與可擴展性。


進一步學習資料

  1. Oracle - Project Loom Documentation
  2. Java 19 Virtual Threads Overview
  3. Virtual Threads in Java 19: A Deep Dive
  4. Java Concurrency in Practice - Chapter 8: Structured Concurrency
  5. Java Design Patterns and Best Practices with Project Loom

核心技能回顧

  • 掌握虛擬線程的基本概念與工作原理。
  • 理解虛擬線程與傳統線程模型的差異及其適用場景。
  • 能夠使用 Thread.startVirtualThread() 創建虛擬線程。
  • 學會結合 CompletableFuture 實現高效的異步編程。
  • 掌握虛擬線程在高并發場景下的性能優勢與最佳實踐。
  • 能夠在實際項目中合理應用虛擬線程,提升系統性能與資源利用率。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/85306.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/85306.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/85306.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux系統移植⑦:uboot啟動流程詳解-board_init_r執行過程

Linux系統移植⑦&#xff1a;uboot啟動流程詳解-board_init_r執行過程 在uboot中&#xff0c;board_init_r 是啟動流程中的一個關鍵函數&#xff0c;負責完成板級&#xff08;board-specific&#xff09;的后期初始化工作。以下是關于該函數的詳細說明&#xff1a; 1. 函數作…

OpenStack入門體驗

1.1云計算概述 相信大家都聽到很多的阿里云、騰訊云、百度云等等這些詞,那到底什么是云計算?云 計算又能做什么? 1.1.1什么是云計算 云計算(cloud computing)是一種基于網絡的超級計算模式,基于用戶的不同需求,提供所需的資源,包括計算資源、存儲資源、網絡資源等。云計算…

RK 安卓10/11平臺 HDMI-IN 調試

這篇文章我們介紹一下在安卓9、10、11的版本上&#xff0c;rk平臺的hdmi-in功能是如何實現的&#xff0c;下篇文章我們再介紹安卓12之后的版本有了什么變化。希望對在rk平臺調試hdmi-in功能的朋友有一些幫助。 目錄 &#xff08;1&#xff09;概述 &#xff08;2&#xff09;…

MongoDB學習記錄(快速入門)

MongoDB核心 基礎概念 數據庫 數據庫是按照數據結構來組織、存儲和管理數據的倉庫。在內存中運行的&#xff0c;一旦程序運行結束或者計算機斷電&#xff0c;程序運行中的數據都會丟失。我們需要將一些程序運行的數據持久化到硬盤之中&#xff0c;以確保數據的安全性。數據庫…

阿里一面:微服務拆分需要考慮什么因素?

要拆分微服務&#xff0c;首先我們要了解微服務拆了會有什么問題&#xff1f;怎么合理拆服務&#xff1f; 拆分服務會帶來什么問題&#xff1f; 舉個電商系統下單扣庫存的例子。 對于單體應用&#xff0c;通訊在進程內部進行&#xff0c;下單方法調用扣庫存方法&#xff0c;…

3D高斯潑濺和4D高斯

1.高斯函數 想象你往平靜的湖水里扔一塊石頭&#xff0c;水波會以石頭落點為中心向外擴散&#xff0c;形成一個逐漸衰減的圓形波紋。高斯函數的形狀就和這個波紋類似&#xff1a; 中心最高&#xff08;石頭落點&#xff0c;波峰最強&#xff09;。越往外&#xff0c;高度&…

comfyui插件和comfyui mac安裝

mac comfyui安裝包 ComfyUI.zip&#xff0c;官方最新0.3.40&#xff0c;如果后續官方有迭代&#xff0c;可以直接通過git更新源碼升級 comfyui插件下載&#xff0c;解壓放到custom_nodes目錄下&#xff0c;包含 comfyui-animatediff-evolved&#xff08;視頻插件&#xff09; 和…

面試題SpringCloud

SpringCloud有哪些特征&#xff1f; 分布式/版本化配置服務注冊與發現路由服務到服務的調用負載均衡斷路器領導選舉和集群狀態分布式消息傳遞 SpringCloud核心組件&#xff1f; Eureka 注冊中心Ribbon 客戶端負載均衡Hystrix&#xff1a; 服務容錯處理Feign:聲明式Rest客戶端Zu…

ASR-PRO語音識別可能出現的問題

ASR-PRO語音識別可能出現的問題 4月份有一天刷到牢大/愛麗絲語音自開關燈設備&#xff0c;心血來潮&#xff0c;博主也是淺嘗了一下&#xff0c;由此也總結一下&#xff0c;實現此項目會出現的問題。 在實現愛麗絲開關燈模塊時ASRPRO語音識別可能出現的問題如下&#xff1a; …

蒼穹外賣--緩存菜品Spring Cache

Spring Cache是一個框架&#xff0c;實現了基于注解的緩存功能&#xff0c;只需要簡單地加一個注解&#xff0c;就能實現緩存功能。 Spring Cache提供了一層抽象&#xff0c;底層可以切換不同的緩存實現&#xff0c;例如&#xff1a; ①EHCache ②Caffeine ③Redis 常用注解…

個人簡歷制作MarkDown模板

MarkDown制作個人簡歷的模板放在了github上&#xff0c;大家如有需求&#xff0c;請自取&#xff1a; https://github.com/QQQQQQBY/ResumeTemplate 介紹一下此模板的特點&#xff1a; &#x1f338;個人面試期間使用的、整理的簡歷格式&#xff0c;現在分享給大家。 ?簡歷采…

【MySQL數據庫 | 第五篇】DDL操作2

文章目錄 當前數據庫student的數據數據表操作 - 修改&刪除&#x1f4d6;修改操作增加字段&#x1f44f;案例&#xff1a;向數據表student中添加字段 id修改字段的數據類型【只能修改字段的屬性】&#x1f44f;案例&#xff1a;將student表中字段age的屬性由tinyint unsigne…

【瀏覽器插件】如何開發一個Chrome瀏覽器插件

這篇文章來介紹一下,如何開發一個自己的Chrome瀏覽器插件程序。 Chrome瀏覽器插件,其實是讓瀏覽器替我們執行我們自己寫的代碼,既然要讓瀏覽器執行代碼,那么首先,就需要定義一個規范,也就是說,需要讓Chrome瀏覽器知道,你寫的程序是一個插件。 這就需要介紹一下插件中…

詳細講解Redis為什么被設計成單線程

Redis 被設計成單線程的原因主要有以下幾點&#xff0c;這些原因涉及性能優化、復雜性控制、數據一致性以及適用場景等多個方面&#xff1a; 1. 簡化設計與實現 避免鎖競爭&#xff1a;多線程環境下&#xff0c;多個線程訪問共享資源時需要加鎖來保證數據一致性。鎖的使用會增…

Hive 邏輯優化器

Optimizer PointLookupOptimizer 作用&#xff1a;把符合條件的 OR 表達式轉為 IN。 參數hive.optimize.point.lookup 設置是否開啟 PointLookupOptimizer&#xff0c;默認為 true. 參數 hive.optimize.point.lookup.min 控制多少個 OR 表達式轉為 IN&#xff0c;默認 31。 例…

ZYNQ Petalinux實戰:PCIe直通NVMe固態硬盤,解鎖存儲性能新極限!

突破SD卡和SATA的速度枷鎖!本文將手把手教你如何在ZYNQ平臺上通過PCIe接口驅動NVMe固態硬盤。從硬件設計、Linux內核配置到創新性的DMA零拷貝優化,實現2000MB/s+ 的存儲性能飛躍,附完整代碼解析和性能實測對比。 一、為什么選擇PCIe NVMe?存儲性能革命 ZYNQ傳統存儲方案面…

05-mcp-server案例分享-用豆包大模型 1.6 手搓文生圖視頻 MCP-server發布到PyPI官網

1前言 上期給大家介紹過mcp-server案例分享-用豆包大模型 1.6 手搓文生圖視頻 MCP-server。當時部署的方式使用了一個私有云SSE的部署。當時缺少一個本地部署的方式&#xff0c;有的小伙伴給我留言能不能有一個本地話部署方式了。今天就給大家帶來一個本地化部署的方案。 話不…

MCP Parameters 增加描述

場景&#xff1a;本地MCP開發完后是否發現CLINE上顯示的Parameters 顯示No description 方法1 &#xff1a;使用參數元數據 (Annotated) 可以使用 Pydantic 的with 類提供有關參數的其他元數據Annotated。這種方法更受歡迎&#xff0c;因為它更現代&#xff0c;并且將類型提示…

STM32 GPIO 寄存器開發

&#x1f527; ?一、核心寄存器概覽? ?寄存器??功能??位寬??關鍵位域??GPIOx_CRL/CRH?配置引腳模式&#xff08;輸入/輸出/復用/模擬&#xff09;和輸出參數32位每4位控制1個引腳&#xff1a;CNF[1:0]&#xff08;模式&#xff09; MODE[1:0]&#xff08;速度&am…

powershell 獲取 用戶及進程列表

在PowerShell中獲取用戶的進程列表&#xff0c;可以通過幾種方法實現。以下是一些常見的方法&#xff1a; 方法1&#xff1a;使用Get-WmiObject Get-WmiObject命令可以用來查詢Windows Management Instrumentation (WMI)數據庫&#xff0c;從而獲取關于進程和用戶的信息。 # …