如果 ForkJoinPool 中的執行緒執行阻塞 I/O 活動(在下面的代碼中使用 模擬Thread.sleep(10000)),它應該選擇另一個不會導致阻塞 IO 的任務。但是,使用 ForkJoinPool 以 1 或 2 的并行度運行以下代碼,結果與它不匹配。執行緒不會放棄阻塞任務(即任務 1 和任務 2)并移動到非阻塞任務(任務 3)。在 pool size =1 的情況下,所有任務按順序執行,而我希望 Task 3 首先完成,因為它在兩種情況下都是非阻塞的( pool size=1 或 2 )
在阻塞 IO 的情況下,ForkJoinPool 中執行緒的實際行為是什么?
ForkJoinPool pool = new ForkJoinPool(1);
List<Future<String>> tasks = new ArrayList<Future<String>>();
//Blocking
tasks.add(pool.submit(() -> { Thread.sleep(10000); System.out.println("Task 1 woke up" Thread.currentThread().isDaemon()); return "task1"; }));
//Blocking
tasks.add(pool.submit(() -> { Thread.sleep(10000); System.out.println("Task 2 woke up" Thread.currentThread().isDaemon()); return "task2"; }));
//Non Blocking
tasks.add(pool.submit(() -> { System.out.println("Task 3 Runs" Thread.currentThread().isDaemon()); return "task3"; }));
int i=0;
System.out.println("pool size = " pool.getParallelism() "Thread count=" pool.getPoolSize() "Stealing =" pool.getStealCount());
System.out.println("waiting");
String str1 = tasks.get(0).get();
String str2 = tasks.get(1).get();
String str3 = tasks.get(2).get();
System.out.println("Results = " str1 str2 str3);
System.out.println("done");
結果 :
//池大小 = 2
任務 2 喚醒真實
任務 1 喚醒真實
任務 3 運行真實
//池大小 = 1
任務 1 喚醒真實
任務 2 喚醒真實
任務 3 運行真實
另一個觀察:
當我們首先提交任務 3(非阻塞)時,只有它首先被呼叫。
uj5u.com熱心網友回復:
如果 ForkJoinPool 中的執行緒執行阻塞 I/O 活動(在下面使用 Thread.sleep(10000) 的代碼中模擬),它應該選擇另一個不會導致阻塞 IO 的任務。
這不是執行緒的行為方式。一個執行緒代表一個正在進行的執行。不能隨意跳轉到另一個Runnable。執行緒無法知道執行緒是否阻塞了 I/O 或執行密集計算,除非執行緒引擎和特定的 I/O 是為此而設計的(例如 jdbc 與 r2dbc)。
換句話說,如果您使用帶有傳統阻塞 I/O 的 Reactor/Spring Reactive/其他一些反應式編程框架,例如 JDBC,您的執行緒仍將掛起等待 I/O。
阻塞 I/O 通常在輪詢套接字時實作為回圈,特定 I/O 之外的任何東西都無法知道這實際上是阻塞 I/O。
據我所知ForkJoinPool,它不是反應式的,它將 Runnables 交給執行緒,就是這樣。
uj5u.com熱心網友回復:
ForkJoinPool 僅用作 Loom 提案中提到的調度程式。只有虛擬執行緒有能力放棄阻塞任務并切換到另一個任務。根據我從 loom 郵件串列中閱讀郵件的記憶,loom 團隊目前不打算重新設計 java.util.concurrent 的 ForkJoinPool 以使用虛擬執行緒。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/417315.html
標籤:
