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

Java 新技術(shù):虛擬線程使用指南

開發(fā)
在對(duì)虛擬線程需要限制并發(fā)數(shù)的場(chǎng)景,使用信號(hào)量即可。在虛擬線程中使用線程局部變量時(shí)要注意避免緩存昂貴的可重用對(duì)象。

虛擬線程是在 Java 21 版本中實(shí)現(xiàn)的一種輕量級(jí)線程。它由 JVM 進(jìn)行創(chuàng)建以及管理。虛擬線程和傳統(tǒng)線程(我們稱之為平臺(tái)線程)之間的主要區(qū)別在于,我們可以輕松地在一個(gè) Java 程序中運(yùn)行大量、甚至數(shù)百萬個(gè)虛擬線程。

本文是繼《Java 21 新技術(shù):虛擬線程使用指南》的第二篇文章,無意全面涵蓋虛擬線程的每個(gè)重要細(xì)節(jié),目的是給大家使用虛擬線程提供一套使用指南,幫助大家能更好使用的虛擬線程,發(fā)揮其作用并避免踩坑。

本文完整大綱如下,

使用信號(hào)量限制并發(fā)

在某些場(chǎng)景下,我們需要限制某個(gè)操作的并發(fā)數(shù)。例如某些外部服務(wù)可能無法同時(shí)處理超過 10 個(gè)并發(fā)請(qǐng)求。

由于平臺(tái)線程是一種寶貴的資源,通常在線程池中進(jìn)行管理,因此線程池的使用對(duì)于如今的程序員相當(dāng)普遍。

比如上面例子要限制并發(fā)請(qǐng)求數(shù),某些人會(huì)使用線程池來處理,代碼如下,

ExecutorService es = Executors.newFixedThreadPool(10);
...
Result foo() {
    try {
        var fut = es.submit(() -> callLimitedService());
        return f.get();
    } catch (...) { ... }
}

上面代碼示例可以確保外部服務(wù)最多只有 10 個(gè)并發(fā)請(qǐng)求,因?yàn)槲覀兊木€程池中只有最多 10 個(gè)線程。

限制并發(fā)只是使用線程池的副產(chǎn)品。線程池旨在共享稀缺資源,而虛擬線程并不稀缺,因此永遠(yuǎn)不應(yīng)該池化虛擬線程!

使用虛擬線程時(shí),如果要限制訪問某些服務(wù)的并發(fā)請(qǐng)求,則應(yīng)該使用專門為此目的設(shè)計(jì)的 Semaphore 類。示例代碼如下,

Semaphore sem = new Semaphore(10);
...
Result foo() {
    sem.acquire();
    try {
        return callLimitedService();
    } finally {
        sem.release();
    }
}

在這個(gè)示例中,同一時(shí)刻只有 10 個(gè)虛擬線程可以進(jìn)入 foo() 方法取得鎖,而其他虛擬線程將會(huì)被阻塞。

簡單地使用信號(hào)量阻塞某些虛擬線程可能看起來與將任務(wù)提交到固定數(shù)量線程池有很大不同,但事實(shí)并非如此。

將任務(wù)提交到等待任務(wù)池會(huì)將它們排隊(duì)處理,信號(hào)量在內(nèi)部(或任何其他阻塞同步構(gòu)造)構(gòu)造了一個(gè)阻塞線程隊(duì)列,這些任務(wù)在阻塞線程隊(duì)列上也會(huì)進(jìn)行排隊(duì)處理。

我們可以將平臺(tái)線程池認(rèn)作是從等待任務(wù)隊(duì)列中提取任務(wù)進(jìn)行處理的工作人員,然后將虛擬線程視為任務(wù)本身,在任務(wù)或者線程可以執(zhí)行之前將會(huì)被阻塞,但任務(wù)或者線程被阻塞時(shí)在計(jì)算機(jī)中的底層表示上實(shí)際是相同的。

這里想告訴大家的就是不管是線程池的任務(wù)排隊(duì),還是信號(hào)量內(nèi)部的線程阻塞,它們之間是由等效性的。在虛擬線程某些需要限制并發(fā)數(shù)場(chǎng)景下,直接使用信號(hào)量即可。

不要在線程局部變量中緩存可重用對(duì)象

虛擬線程支持線程局部變量,就像平臺(tái)線程一樣。通常線程局部變量用于將一些特定于上下文的信息與當(dāng)前運(yùn)行的代碼關(guān)聯(lián)起來,例如當(dāng)前事務(wù)和用戶 ID。

對(duì)于虛擬線程來說,使用線程局部變量是完全合理的。但是如果考慮更安全、更有效的線程局部變量,可以使用 Scoped Values。

更多有關(guān) Scoped Values 介紹,請(qǐng)參閱 https://docs.oracle.com/en/java/javase/21/core/scoped-values.html#GUID-9A4565C5-82AE-4F03-A476-3EAA9CDEB0F6

線程局部變量有一種用途與虛擬線程是不太適合的,那就是緩存可重用對(duì)象。

可重用對(duì)象的創(chuàng)建成本通常很高,通常消耗大量內(nèi)存且可變,還不是線程安全的。它們被緩存在線程局部變量中,以減少它們實(shí)例化的次數(shù)以及它們?cè)趦?nèi)存中的實(shí)例數(shù)量,好處是它們可以被線程上不同時(shí)間運(yùn)行的多個(gè)任務(wù)重用,減少昂貴對(duì)象創(chuàng)建的開銷。

例如 SimpleDateFormat 的實(shí)例創(chuàng)建成本很高,而且不是線程安全的。為了解決創(chuàng)建成本、線程不安全問題,通常是將此類實(shí)例緩存在 ThreadLocal 中,如下例所示:

static final ThreadLocal<SimpleDateFormat> cachedFormatter =
       ThreadLocal.withInitial(SimpleDateFormat::new);

void foo() {
  ...
 cachedFormatter.get().format(...);
 ...
}

僅當(dāng)線程(以及因此在線程本地緩存的昂貴對(duì)象)被多個(gè)任務(wù)共享和重用時(shí)(就像平臺(tái)線程被池化時(shí)的情況一樣),這種緩存才有用。許多任務(wù)在線程池中運(yùn)行時(shí)可能會(huì)調(diào)用 foo,但由于池中僅包含幾個(gè)線程,因此該對(duì)象只會(huì)被實(shí)例化幾次(每個(gè)池線程一次)并被緩存和重用。

但是虛擬線程永遠(yuǎn)不會(huì)被池化,也不會(huì)被不相關(guān)的任務(wù)重用。因?yàn)槊總€(gè)任務(wù)都有自己的虛擬線程,所以每次從不同任務(wù)調(diào)用 foo 都會(huì)觸發(fā)新 SimpleDateFormat 的實(shí)例化。而且由于可能有大量的虛擬線程同時(shí)運(yùn)行,昂貴的對(duì)象可能會(huì)消耗相當(dāng)多的內(nèi)存。這些結(jié)果與線程本地緩存想要實(shí)現(xiàn)的結(jié)果恰恰相反。

對(duì)于線程局部變量緩存可重用對(duì)象的問題,沒有什么好的通用替代方案,但對(duì)于 SimpleDateFormat,我們應(yīng)該將其替換為 DateTimeFormatter。DateTimeFormatter 是不可變的,因此單個(gè)實(shí)例就可以由所有線程共享:

static final DateTimeFormatter formatter = DateTimeFormatter….;

void foo() {
  ...
 formatter.format(...);
 ...
}

需要注意的是,使用線程局部變量來緩存共享的昂貴對(duì)象有時(shí)是由一些異步框架在幕后完成的,其隱含的假設(shè)是這些可重用對(duì)象只會(huì)由極少數(shù)池線程使用。

所以混合虛擬線程和異步框架一起使用可能不是一個(gè)好主意,對(duì)某些方法的調(diào)用可能會(huì)導(dǎo)致可重用對(duì)象被重復(fù)創(chuàng)建。

避免長時(shí)間和頻繁的 synchronized

當(dāng)前虛擬線程實(shí)現(xiàn)由一個(gè)限制是,在同步塊或方法內(nèi)執(zhí)行 synchronized 阻塞操作會(huì)導(dǎo)致 JDK 的虛擬線程調(diào)度程序阻塞寶貴的操作系統(tǒng)線程,而如果阻塞操作是在同步塊或方法外完成的,則不會(huì)被阻塞。我們稱這種情況為 “Pinning”。

如果阻塞操作既長期又頻繁,則 “Pinning” 可能會(huì)對(duì)服務(wù)器的吞吐量產(chǎn)生不利影響。如果阻塞操作短暫(例如內(nèi)存中操作)或不頻繁則可能不會(huì)產(chǎn)生不利影響。

為了檢測(cè)可能有害的 “Pinning” 實(shí)例,(JDK Flight Recorder (JFR) 在 “Pinning” 阻塞時(shí)間超過 20 毫秒時(shí),會(huì)發(fā)出 jdk.VirtualThreadPinned 事件。

或者我們可以使用系統(tǒng)屬性 jdk.tracePinnedThreads 在線程被 “Pinning” 阻塞時(shí)發(fā)出堆棧跟蹤。

啟動(dòng) Java 程序時(shí)添加 -Djdk.tracePinnedThreads=full 運(yùn)行,會(huì)在線程被 “Pinning” 阻塞時(shí)打印完整的堆棧跟蹤,突出顯示本機(jī)幀和持有監(jiān)視器的幀。使用 -Djdk.tracePinnedThreads=short 運(yùn)行,會(huì)將輸出限制為僅有問題的幀。

如果這些機(jī)制檢測(cè)到既長期又頻繁 “Pinning” 的地方,請(qǐng)?jiān)谶@些特定地方將 synchronized 替換為 ReentrantLock。以下是長期且頻繁使用 synchronized 的示例:

synchronized(lockObj) {
    frequentIO();
}

我們可以將其替換為以下內(nèi)容:

lock.lock();
try {
    frequentIO();
} finally {
    lock.unlock();
}

參考資料:https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-E695A4C5-D335-4FA4-B886-FEB88C73F23E

最后說兩句

針對(duì)虛擬線程的使用,相信大家心里已經(jīng)有了答案。在對(duì)虛擬線程需要限制并發(fā)數(shù)的場(chǎng)景,使用信號(hào)量即可。在虛擬線程中使用線程局部變量時(shí)要注意避免緩存昂貴的可重用對(duì)象。對(duì)于使用到 synchronized 同步塊或者方法的虛擬線程,建議替換為 ReentrantLock,避免影響吞吐量。

責(zé)任編輯:趙寧寧 來源: waynblog
相關(guān)推薦

2023-12-28 08:45:25

虛擬線程Java 21

2022-09-29 09:07:08

DataGrip數(shù)據(jù)倉庫數(shù)據(jù)庫

2023-11-03 07:50:01

2012-12-26 12:41:14

Android開發(fā)WebView

2011-07-21 14:57:34

jQuery Mobi

2021-07-27 10:09:27

鴻蒙HarmonyOS應(yīng)用

2009-12-28 17:40:10

WPF TextBox

2010-09-06 14:24:28

ppp authent

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組件

2022-06-23 08:01:36

FlaskSocketIOSwift

2019-11-13 12:39:26

Python 開發(fā)編程語言

2024-02-04 00:00:00

Loki性能查詢

2009-11-30 13:15:27

PHP模板Smarty

2024-02-18 12:44:22

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 久久久久久久一区 | av网站在线播放 | 久久亚洲欧美日韩精品专区 | 在线看无码的免费网站 | 精品福利一区二区三区 | 久久久青草| 国产一区二区三区在线 | 国产精品不卡一区 | avhd101在线成人播放 | 二区在线观看 | 欧美一级在线观看 | 国内久久精品 | 一区二区手机在线 | 精品九九久久 | 亚洲精品麻豆 | 91精品久久久久久久久 | 涩涩导航 | 夜夜骑综合 | 一区二区三区亚洲精品国 | 欧洲毛片| 国产精品18久久久久久白浆动漫 | 日韩视频―中文字幕 | 久久久久久久久久久久91 | 天堂在线www | 一区不卡在线观看 | 91免费视频 | 91免费电影 | 国产精品一区二区在线免费观看 | 欧美一级二级在线观看 | 国产电影精品久久 | 欧美极品一区二区 | www.日本在线 | a久久| 国产成人精品一区二区三区在线 | 羞羞午夜 | 久久成人精品 | 日本不卡免费新一二三区 | 在线看h | 国产精品久久久久久久久免费 | 久久欧美高清二区三区 | 在线中文字幕国产 |