面試官:為什么沒有虛擬線程池?

Java 官方文檔明確指出:
“Do not pool virtual threads.
虛擬線程不是昂貴資源,永遠(yuǎn)不應(yīng)該被池化。
應(yīng)該為每個(gè)任務(wù)創(chuàng)建一個(gè)新的虛擬線程,它們應(yīng)該是短暫的、任務(wù)級(jí)別的。
這是為什么呢?為什么只有虛擬線程 Virtual Thread,卻沒有虛擬線程池 Virtual Thread Pool 呢?
主要原因
之所以只有虛擬線程是因?yàn)椋?/span>虛擬線程創(chuàng)建成本極低,低到其創(chuàng)建成本遠(yuǎn)小于線程池的管理成本。
“也就是說,線程池的管理成本遠(yuǎn)遠(yuǎn)大于虛擬線程的創(chuàng)建成本,所以使用虛擬線程池是一個(gè)不劃算的操作。
具體來說,傳統(tǒng)平臺(tái)線程的創(chuàng)建涉及分配大量的棧內(nèi)存(通常~1MB)并與操作系統(tǒng)交互,開銷很大。池化是為了復(fù)用這些“昂貴”的線程,避免反復(fù)申請(qǐng)資源。而虛擬線程由 JVM 在用戶態(tài)管理,初始??臻g很?。s幾百字節(jié)),創(chuàng)建和銷毀的代價(jià)極低,池化帶來的收益遠(yuǎn)小于管理池本身的復(fù)雜度。
用完就扔”比“池化復(fù)用”更高效、更簡單。一個(gè)線程約等于幾千個(gè)虛擬線程。
一任務(wù)一虛線程的理念
官方推薦并為每個(gè)任務(wù)創(chuàng)建一個(gè)全新的虛擬線程,例如通過 Executors.newVirtualThreadPerTaskExecutor(),任務(wù)完成后虛擬線程即被丟棄。這種模式代碼更清晰,避免了因線程復(fù)用可能帶來的線程局部變量(ThreadLocal)污染等問題,也無需擔(dān)心池的大小調(diào)優(yōu)等問題。
最佳實(shí)現(xiàn)代碼:
// 無需池化 - 直接創(chuàng)建
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
} // 自動(dòng)關(guān)閉(所有虛擬線程完成即銷毀)ExecutorService 并不是一個(gè)傳統(tǒng)意義上的“池”,你可以把它理解為一個(gè)虛擬線程工廠。每次 submit 一個(gè)任務(wù),它都會(huì)立即創(chuàng)建一個(gè)新的虛擬線程來執(zhí)行該任務(wù),它內(nèi)部并不維護(hù)(一個(gè)可復(fù)用的)線程隊(duì)列。
如何限制并發(fā)?
在單進(jìn)程百萬虛擬線程的情況下, JVM 內(nèi)存是完全無壓力的。如果你還是擔(dān)心太多的虛擬線程會(huì)導(dǎo)致程序崩潰,在特定的場景可以使用 Semaphore 等技術(shù)來實(shí)現(xiàn)局部限流,例如以下代碼這樣:
// 使用信號(hào)量而非線程池來限制對(duì)某個(gè)資源的并發(fā)訪問
Semaphore semaphore = new Semaphore(100000); // 限制最大并發(fā)數(shù)為100000
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
executor.submit(() -> {
semaphore.acquire(); // 獲取許可,若已達(dá)上限則阻塞等待
try {
// 訪問受保護(hù)的資源或執(zhí)行需要限流的操作
callLimitedService();
} finally {
semaphore.release(); // 釋放許可
}
});
}
}小結(jié)
虛擬線程 Virtual Thread 因?yàn)槠鋭?chuàng)建成本極低(約幾百字節(jié)),所以不會(huì)完全不需要使用池化技術(shù)來實(shí)現(xiàn),因?yàn)槌鼗夹g(shù)的本質(zhì)是復(fù)用那些“昂貴”的線程,避免反復(fù)申請(qǐng)資源的。如果要局部限流虛擬線程可以使用 Semaphore 來實(shí)現(xiàn)。
































