Java虛擬線程與線程池:為什么重復提交同一個虛擬線程到`newVirtualThreadPerTaskExecutor()`會失效?

Java虛擬線程與線程池:為什么重復提交同一個虛擬線程到`newVirtualThreadPerTaskExecutor()`會失效?

Java虛擬線程與線程池的巧妙協作:深入探討newVirtualThreadPerTaskExecutor()的特性

本文分析一個Java虛擬線程在Executors.newVirtualThreadPerTaskExecutor()創建的線程池中執行的特殊問題。代碼示例中的methods5函數嘗試重復提交同一個預創建的虛擬線程到線程池,但未打印預期日志;而methods6函數使用傳統線程和Executors.newFixedThreadPool()則正常運行。這背后的原因是什么呢?

讓我們來看問題代碼:

private static void methods5() {     ThreadFactory tf = Thread.ofVirtual().factory();     try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {         Thread vt = tf.newThread(() -> log.info("vt task executed."));         for (int i = 0; i < 10; i++) {             executor.submit(vt);         }     } }  private static void methods6() {     try (ExecutorService executor = Executors.newFixedThreadPool(10)) {         for (int i = 0; i < 10; i++) {             executor.submit(() -> log.info("thread task executed."));         }     } }

methods5函數的核心問題在于它將同一個虛擬線程對象vt重復提交到線程池。Executors.newVirtualThreadPerTaskExecutor()的設計初衷是為每個提交的任務創建一個新的虛擬線程,而代碼卻重復使用同一個vt,導致后續提交被忽略。

立即學習Java免費學習筆記(深入)”;

解決方法如下:

方法一:為每個任務提交新的虛擬線程

private static void methods5() {     try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {         for (int i = 0; i < 10; i++) {             executor.submit(() -> System.out.println("vt task executed."));         }     } }

方法二:利用Lambda表達式,讓線程池為每個任務創建新的虛擬線程 (與方法一效果相同,只是代碼更簡潔)

需要注意的是,由于虛擬線程創建和銷毀的開銷極低,使用Executors.newVirtualThreadPerTaskExecutor()進行線程池化的必要性并不高,甚至可能違背虛擬線程的設計初衷。直接使用Thread.ofVirtual().start()啟動虛擬線程通常是更優的選擇。 使用線程池更適合管理有限的物理線程資源,而虛擬線程本身就具有極高的并發能力。

以上就是Java虛擬線程與線程池:

? 版權聲明
THE END
喜歡就支持一下吧
點贊9 分享