Executor 將提交 Runnable 與決定其執行位置分開。ExecutorService 增加生命週期管理與 submit;Callable<V> 可以回傳值或擲出受檢查例外,而 Future<V> 代表最終結果。Future.get() 會建立工作完成前由工作執行之動作所需的可見性。
Future<Result> future = pool.submit(() -> compute(input));
try {
return future.get();
} catch (ExecutionException e) {
throw new ServiceException(e.getCause());
}使用 synchronized、Lock、原子操作、並行集合或訊息傳遞來建立 happens-before 關係。執行器提供排程,但不會自動確保可變共用物件的安全性。
AQS 與同步器 #
AbstractQueuedSynchronizer(AQS)是鎖、Semaphore、Latch 與相關同步器的框架。子類別會維護原子整數狀態,並實作取得/釋放嘗試。發生競爭時,AQS 會將等待執行緒加入 FIFO 風格的同步佇列,並以 LockSupport 暫停它們;釋放時會喚醒符合條件的後繼者。Condition 使用相關的條件佇列,並在收到訊號時將等待者移回同步佇列。佇列順序本身不是普遍的公平性保證。
ThreadPoolExecutor 接納 #
ThreadPoolExecutor 會先建立工作者,直到達到 corePoolSize;接著將工作排入佇列;只有佇列拒絕工作時,才會向 maximumPoolSize 增長;之後便拒絕工作。因此,無界的 LinkedBlockingQueue 實際上會阻止執行緒數超過核心執行緒,而 SynchronousQueue 會積極建立工作者,直到達到上限。核心大小以上的閒置工作者會在 keepAliveTime 後終止;明確啟用時,核心執行緒也可能逾時。
根據工作負載證據、記憶體限制與下游系統容量選擇有界佇列並設定大小。工作者工廠會控制名稱、daemon 狀態與未捕捉例外處理。AbortPolicy 會擲出例外,CallerRunsPolicy 讓提交者執行工作以施加反壓,DiscardPolicy 會捨棄工作,而 DiscardOldestPolicy 會在重試前移除佇列中的工作。只有呼叫者可以容忍時,才可靜默捨棄工作。
生命週期、取消與可見性 #
cancel(true) 會將 Future 標記為已取消,並在工作執行中時要求中斷;中斷是協作式的,因此阻塞操作必須傳播或恢復中斷狀態,而 CPU 密集工作必須輪詢它。取消不會回復副作用。
shutdown() 會拒絕新工作,同時允許佇列中的工作完成。shutdownNow() 會嘗試中斷工作者,並回傳尚未開始的工作。在應用程式邊界呼叫 awaitTermination。目前的 JDK 中,Executors 工廠方法提供固定執行緒、單執行緒、排程、工作竊取與虛擬執行緒執行器,但明確建立 ThreadPoolExecutor 能讓佇列與拒絕原則可供檢查。當 ExecutorService 的生命週期是詞法範圍時,請務必關閉它。
評論
在 GitHub 上閱讀或評論(發表評論需要登入)