成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java 21 神仙特性:虛擬線程使用指南

開發 前端
針對廣播模式和其他常見的并發模式,如果希望有更好的可觀察性,建議使用結構化并發。這是 Java 21 中新出的特性,這里給大家賣個關子,我將在后續進行講解。

虛擬線程是由 Java 21 版本中實現的一種輕量級線程。它由 JVM 進行創建以及管理。虛擬線程和傳統線程(我們稱之為平臺線程)之間的主要區別在于,我們可以輕松地在一個 Java 程序中運行大量、甚至數百萬個虛擬線程。

由于虛擬線程的數量眾多,也就賦予了 Java 程序強大的力量。虛擬線程適合用來處理大量請求,它們可以更有效地運行 “一個請求一個線程” 模型編寫的 web 應用程序,可以提高吞吐量以及減少硬件浪費。

由于虛擬線程是 java.lang.Thread 的實現,并且遵守自 Java SE 1.0 以來指定 java.lang.Thread 的相同規則,因此開發人員無需學習新概念即可使用它們。

但是虛擬線程才剛出來,對我們來說有一些陌生。由于 Java 歷來版本中無法生成大量平臺線程(多年來 Java 中唯一可用的線程實現),已經讓程序員養成了一套關于平臺線程的使用習慣。這些習慣做法在應用于虛擬線程時會適得其反,我們需要摒棄。

此外虛擬線程和平臺線程在創建成本上的巨大差異,也提供了一種新的關于線程使用的方式。Java 的設計者鼓勵使用虛擬線程而不必擔心虛擬線程的創建成本。

本文無意全面涵蓋虛擬線程的每個重要細節,目的只是提供一套介紹性指南,以幫助那些希望開始使用虛擬線程的人充分利用它們。

關于更多有關虛擬線程和平臺線程的介紹,大家可以看我《3 分鐘理解 Java 虛擬線程》這篇文章有詳細講解。

本文完整大綱如下,

圖片圖片

請大方使用同步阻塞 IO

虛擬線程可以顯著提高以 “一個請求一個線程” 模型編寫的 web 應用程序的吞吐量(注意不是延遲)。在這種模型中,web 應用程序針對每個客戶端請求都會創建一個線程進行處理。因此為了處理更多的客戶端請求,我們需要創建更多的線程。

在 “一個請求一個線程” 模型中使用平臺線程的成本很高,因為平臺線程與操作系統線程對應(操作系統線程是一種相對稀缺的資源),阻塞了平臺線程,會讓它無事可做一直處于阻塞中,這樣就會造成很大的資源浪費。

然而,在這個模型中使用虛擬線程就很合適,因為虛擬線程非常廉價就算被阻塞也不會造成資源浪費。因此在虛擬線程出來后,Java 的設計者是建議我們應該以簡單的同步風格編寫代碼并使用阻塞 IO。

舉個例子,以下用非阻塞異步風格編寫的代碼是不會從虛擬線程中受益太多的,

CompletableFuture.supplyAsync(info::getUrl, pool)
   .thenCompose(url -> getBodyAsync(url, HttpResponse.BodyHandlers.ofString()))
   .thenApply(info::findImage)
   .thenCompose(url -> getBodyAsync(url, HttpResponse.BodyHandlers.ofByteArray()))
   .thenApply(info::setImageData)
   .thenAccept(this::process)
   .exceptionally(t -> { t.printStackTrace(); return null; });

另一方面,以下用同步風格并使用阻塞 IO 編寫的代碼使用虛擬線程將受益匪淺,

try {
   String page = getBody(info.getUrl(), HttpResponse.BodyHandlers.ofString());
   String imageUrl = info.findImage(page);
   byte[] data = getBody(imageUrl, HttpResponse.BodyHandlers.ofByteArray());
   info.setImageData(data);
   process(info);
} catch (Exception ex) {
   t.printStackTrace();
}

并且上面的同步代碼也更容易在調試器中調試、在分析器中分析或通過線程轉儲進行觀察。要觀察虛擬線程,可以使用 jcmd 命令創建線程轉儲,

jcmd <pid> Thread.dump_to_file -format=json <file>

用同步風格并使用阻塞 IO 風格編寫的代碼越多,虛擬線程的性能和可觀察性就越好。而用異步非阻塞 IO 風格編寫的程序或框架,如果每個任務沒有專用一個線程,則無法從虛擬線程中獲得顯著的好處。

使用虛擬線程,我們因該避免將同步阻塞 IO 與異步非阻塞 IO 混為一談。

避免池化虛擬線程

關于虛擬線程使用方面最難理解的一件事情就是,我們不應該池化虛擬線程。雖然虛擬線程具有與平臺線程相同的行為,但虛擬線程和線程池其實是兩種概念。

平臺線程是一種稀缺資源,因為它很寶貴。越寶貴的資源就越需要管理,管理平臺線程最常見的方法是使用線程池。

不過在使用線程池后,我們需要回答的一個問題,線程池中應該有多少個線程?最小線程數、最大線程數應該設置多少?這也是一個問題。

虛擬線程是一種非常廉價的資源,每個虛擬線程不應代表某些共享的、池化的資源,而應代表單一任務。在應用程序中,我們應該直接使用虛擬線程而不是通過線程池使用它。

那么我們應該創建多少個虛擬線程嘞?答案是不必在乎虛擬線程的數量,我們有多少個并發任務就可以有多少個虛擬線程。

如下是一段提交任務的代碼,將每個任務都提交到線程池中執行,在 Java 21 以后,不建議再使用共享線程池執行器,代碼如下,

Future<ResultA> f1 = sharedThreadPoolExecutor.submit(task1);
Future<ResultB> f2 = sharedThreadPoolExecutor.submit(task2);
// ... use futures

建議使用虛擬線程執行器,代碼如下,

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
   Future<ResultA> f1 = executor.submit(task1);
   Future<ResultB> f2 = executor.submit(task2);
   // ... use futures
}

上面代碼雖然仍使用 ExecutorService,但從 Executors.newVirtualThreadPerTaskExecutor() 方法返回的執行器不再使用線程池。它會為每個提交的任務都創建一個新的虛擬線程。

此外,ExecutorService 本身是輕量級的,我們可以像創建任何簡單對象一樣直接創建一個新的 ExecutorService 對象而不必考慮復用。

這使我們能夠依賴 Java 19 中新添加的 ExecutorService.close() 方法和 try-with-resources 語法糖。在 try 塊末尾隱式調用 ExecutorService.close() 方法,會自動等待提交給 ExecutorService 的所有任務(即 ExecutorService 生成的所有虛擬線程)終止。

對于廣播場景來說,使用 Executors.newVirtualThreadPerTaskExecutor() 比較合適,在這種場景中,希望同時對不同的服務執行多個傳出調用,并且方法結束時就關閉線程池,代碼如下,

void handle(Request request, Response response) {
    var url1 = ...
    var url2 = ...

    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
        var future1 = executor.submit(() -> fetchURL(url1));
        var future2 = executor.submit(() -> fetchURL(url2));
        response.send(future1.get() + future2.get());
    } catch (ExecutionException | InterruptedException e) {
        response.fail(e);
    }
}

String fetchURL(URL url) throws IOException {
    try (var in = url.openStream()) {
        return new String(in.readAllBytes(), StandardCharsets.UTF_8);
    }
}

針對廣播模式和其他常見的并發模式,如果希望有更好的可觀察性,建議使用結構化并發。這是 Java 21 中新出的特性,這里給大家賣個關子,我將在后續進行講解。

根據經驗來說,如果我們的應用程序從未經歷 1 萬的并發訪問,那么它不太可能從虛擬線程中受益。一方面它負載太輕而不需要更高的吞吐量,一方面并發請求任務也不夠多。

參考資料

責任編輯:武曉燕 來源: waynblog
相關推薦

2024-01-12 16:12:44

Java虛擬線程開發

2023-10-23 19:51:11

Java線程

2023-10-09 08:18:08

域值Java 21結構化

2022-09-29 09:07:08

DataGrip數據倉庫數據庫

2024-08-23 15:34:23

JavaScrip數組

2012-12-26 12:41:14

Android開發WebView

2023-11-03 07:50:01

2010-09-06 14:24:28

ppp authent

2011-07-21 14:57:34

jQuery Mobi

2021-07-27 10:09:27

鴻蒙HarmonyOS應用

2009-12-28 17:40:10

WPF TextBox

2009-12-31 17:17:45

Silverlight

2021-01-12 15:19:23

Kubernetes

2017-01-04 15:22:57

TrimPath模板引擎

2010-06-03 17:27:36

Hadoop命令

2010-08-04 15:37:31

Flex圖表

2010-08-05 15:40:21

FlexBuilder

2010-08-04 14:28:01

Flex組件

2019-11-13 12:39:26

Python 開發編程語言

2024-02-04 00:00:00

Loki性能查詢
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人在线视频一区 | 91精品一区二区三区久久久久久 | 老妇激情毛片免费 | 日韩毛片 | 午夜不卡福利视频 | 国产精品国产三级国产aⅴ中文 | 日p视频免费看 | 国产中文一区二区三区 | 午夜tv免费观看 | 欧美成年视频 | 四虎影院新地址 | 国产超碰人人爽人人做人人爱 | 精品国产鲁一鲁一区二区张丽 | 999精品视频在线观看 | 天天综合干 | 在线成人av | 国产午夜精品一区二区 | 午夜免费电影院 | 精品综合视频 | 精品亚洲一区二区三区 | 国产9 9在线 | 中文 | 免费观看的黄色网址 | 国产精品96久久久久久 | 日韩视频在线一区 | 亚洲色欧美另类 | 狠狠操网站 | 亚洲另类春色偷拍在线观看 | 国产精品国产成人国产三级 | 亚洲免费在线观看av | 国产精品久久久久一区二区三区 | 日本在线中文 | 亚洲97| 国产香蕉视频在线播放 | 国产精品毛片无码 | 久久男人 | 国产精品69av | 日本视频免费观看 | 真人女人一级毛片免费播放 | www性色| 成人福利在线 | 中文欧美日韩 |