Java的虛擬線程(協程)特性開啟預覽階段,多線程開發的難度將大大降低

来源:https://www.cnblogs.com/felordcn/archive/2022/04/08/16115793.html
-Advertisement-
Play Games

高併發、多線程一直是Java編程中的難點,也是面試題中的要點。Java開發者也一直在嘗試使用多線程來解決應用伺服器的併發問題。但是多線程並不容易,為此一個新的技術出現了,這就是虛擬線程。 傳統多線程的痛點 但是編寫多線程代碼是非常不容易的,難以控制的執行順序,共用變數的線程安全性,異常的可觀察性等等 ...


高併發、多線程一直是Java編程中的難點,也是面試題中的要點。Java開發者也一直在嘗試使用多線程來解決應用伺服器的併發問題。但是多線程並不容易,為此一個新的技術出現了,這就是虛擬線程。

傳統多線程的痛點

但是編寫多線程代碼是非常不容易的,難以控制的執行順序,共用變數的線程安全性,異常的可觀察性等等都是多線程編程的難點。

如果每個請求在請求的持續時間內都在一個線程中處理,那麼為了提高應用程式的吞吐量,線程的數量必須隨著吞吐量的增長而增長。不幸的是線程是稀缺資源,創建一個線程的代價是昂貴的,即使引入了池化技術也無法降低新線程的創建成本,而且 JDK 當前的線程實現將應用程式的吞吐量限制在遠低於硬體可以支持的水平。

為此很多開發人員轉向了非同步編程,例如CompletableFuture或者現在正熱的反應式框架。但是這些技術要麼擺脫不了“回調地獄”,要麼缺乏可觀測性。

解決這些痛點、增強Java平臺的和諧,實現每個請求使用獨立線程(thread-per-request style)這種風格成為必要之舉。能否實現一種“成本低廉”的虛擬線程來映射到系統線程以減少對系統線程的直接操作呢?思路應該是沒問題的!於是Java社區發起了關於虛擬線程的JEP 425提案。

虛擬線程

虛擬線程(virtual threads)應該非常廉價而且可以無需擔心系統硬體資源被大量創建,並且不應該被池化。應該為每個應用程式任務創建一個新的虛擬線程。因此,大多數虛擬線程將是短暫的並且具有淺層調用堆棧,只執行單個任務 HTTP 客戶端調用或單個 JDBC 查詢。與之對應的平臺線程( Platform Threads,也就是現在傳統的JVM線程 )是重量級且昂貴的,因此通常必須被池化。它們往往壽命長,有很深的調用堆棧,並且在許多任務之間共用。

總而言之,虛擬線程保留了與 Java 平臺的設計相協調的、可靠的獨立請求線程(thread-per-request style),同時優化了硬體的利用。使用虛擬線程不需要學習新概念,甚至需要改掉現在操作多線程的習慣,使用更加容易上手的API、相容以前的多線程設計、並且絲毫不會影響代碼的拓展性。

平臺線程和虛擬線程的不同

為了更好理解這一個設計,草案對這兩種線程進行了比較。

現在的線程

現在每個java.lang.Thread都是一個平臺線程,平臺線程在底層操作系統線程上運行 Java 代碼,併在代碼的整個生命周期內捕獲操作系統線程。平臺線程數受限於 OS 線程數。

平臺線程並不會因為加入虛擬線程而退出歷史舞臺。

未來的虛擬線程

虛擬線程是由 JDK 而不是操作系統提供的線程的輕量級實現。它們是用戶模式線程的一種形式,在其他多線程語言中已經成功(比如Golang中的協程和Erlang中的進程)。 虛擬線程採用 M:N 調度,其中大量 (M) 虛擬線程被調度為在較少數量 (N) 的 OS 線程上運行。 JDK 的虛擬線程調度程式是一種ForkJoinPool工作竊取的機制,以 FIFO 模式運行。

我們可以很隨意地創建10000個虛擬線程:

// 預覽代碼
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
}  

無需擔心硬體資源是否扛得住,反過來如果你使用Executors.newCachedThreadPool()創建10000個平臺線程,在大多數操作系統上很容易因資源不足而崩潰。

為吞吐量而設計

但是這裡依然要說明一點,虛擬線程並是為了提升執行速度而設計。它並不比平臺線程速度快,它們的存在是為了提供規模(更高的吞吐量),而不是速度(更低的延遲)。它們的數量可能比平臺線程多得多,因此根據利特爾定律,它們可以實現更高吞吐量所需的更高併發性。

換句話說,虛擬線程可以顯著提高應用程式吞吐量

  • 併發任務的數量很高(超過幾千個),並且

  • 工作負載不受 CPU 限制,因為在這種情況下,擁有比處理器內核多得多的線程並不能提高吞吐量。

虛擬線程有助於提高傳統伺服器應用程式的吞吐量,正是因為此類應用程式包含大量併發任務,這些任務花費大量的時間等待。

增強可觀測性

編寫清晰的代碼並不是全部。對正在運行的程式狀態的清晰表示對於故障排除、維護和優化也很重要,JDK 長期以來一直提供調試、分析和監視線程的機制。 在虛擬線程中也會增強代碼的可觀測性,讓開發人員更好地調試代碼。

新的線程API

為此增加了新的線程API設計,目前放出的部分如下:

  • Thread.Builder 線程構建器。

  • ThreadFactory 能批量構建相同特性的線程工廠。

  • Thread.ofVirtual() 創建一個虛擬線程。

  • Thread.ofPlatform() 創建一個平臺線程。

  • Thread.startVirtualThread(Runnable) 一種創建然後啟動虛擬線程的便捷方式。

  • Thread.isVirtual() 測試線程是否是虛擬線程。

還有很多就不一一演示了,有興趣的自行去看JEP425

總結

JEP425還有很多的細節,基於我個人理解能力的不足只能解讀這麼多了。協程在Java社區已經呼喚了很久了,現在終於有了實質性的動作,這是一個令人振奮的好消息。不過這個功能涉及的東西還是很多的,包括平臺線程的相容性、對ThreadLocal的一些影響、對JUC的影響。可能需要多次預覽才能最終落地。胖哥可能趕不上那個時候了,不過很多年輕的同學應該能夠趕上。

關註公眾號:Felordcn 獲取更多資訊

個人博客:https://felord.cn

博主:碼農小胖哥
出處:felord.cn
本文版權歸原作者所有,不可商用,轉載需要聲明出處,否則保留追究法律責任的權利。如果文中有什麼錯誤,歡迎指出。以免更多的人被誤導。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 我們在觀看視頻的時候,有時候會出現一些奇怪的馬賽克,影響我們的觀影體驗,那麼這些馬賽克是如何精確的加上去的呢? 本次我們就來用Python實現對視頻自動打碼! 準備工作 環境咱們還是使用 Python3.8 和 pycharm2021 即可 實現原理 將視頻分為音頻和畫面; 畫面中出現人臉和目標比對 ...
  • strings.Builder 源碼解析、 存在意義、 實現原理、 常用方法、 寫入方法、 擴容方法、 String() 方法、 禁止複製、 線程不安全、 io.Writer 介面、 代碼、 strings.Join 源... ...
  • 最近《孤勇者》這首歌特別火,我也覺得很好聽,不得不給陳奕迅點一個大大的贊。今天想用Python來做一個《孤勇者》的畫圖以及音樂可視化。 python里有個叫做 turtle 的庫,用它提供的方法可以很簡單的畫線和塗色: Python學習交流Q群:906715085#### import turtle ...
  • 作者:xbhog 鏈接:www.cnblogs.com/xbhog/p/15207278.html 異常處理: 背景: 最近在搭建屬於自己的個人博客(碼農小白的執念),自己搭建後端的時候首先考慮的是異常處理。個人也是一邊學習一邊做,難免有疏漏的地方,希望朋友們在不對的地方提醒下。 技術棧: spri ...
  • 最近這段時間,一些互聯網大廠把裁員稱為“畢業”的話題被熱議了很久。 上午,DD在網上瞎逛看到了一篇文章,似乎找了這一做法的祖先。原來這麼有“創意”的操作,很好多年前的漂亮過就已經有了,所以其實這也是個舶來品? 在這篇發表於2016年4月的文章中,據作者稱:他在軟體公司HubSpot工作了近兩年,當有 ...
  • 前言 在github中經常可以看到下麵的日曆圖,可以用來表示每一天在github上的活躍程度。 類似的方法也可以用到空氣質量的可視化方式中來,只要有每天的空氣質量指數就可以。 數據 我這裡使用的是2020年北京市各個監測站點的空氣質量觀測數據,原始數據包含PM2.5,PM10,AQI指數,這裡選擇A ...
  • 前排提醒: 由於 Microsoft Docs 全是機翻。所以本文表格是我人腦補翻+審校。 如果有紕漏、模糊及時評論反饋。 序列式容器 序列容器是指在邏輯上以線性排列方式存儲給定類型元素的容器。 這些容器和數組非常類似,都是在邏輯上連續的(但記憶體不一定是連續的),與數組不同的是,容器可以非常方便的動 ...
  • 前言 今天玩啥?10行代碼夠玩嗎? Python憑藉其簡潔的代碼,贏得了許多開發者的喜愛。因此也就促使了更多開發者用Python開發新的模塊,從而形成良性迴圈, Python可以憑藉更加簡短的代碼實現許多有趣的操作。下麵我們來看看,我們用不超過10行代碼能實現些什麼有趣的功能。 一、生成二維碼 二維 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...