天天看點

多線程程式設計學習十(線程池原理).

一、線程池工作流程

多線程程式設計學習十(線程池原理).
  1. 線程池判斷核心線程池裡的線程是否都在執行任務。如果不是,則建立一個新的工作線程來執行任務(需要獲得全局鎖)。如果核心線程池裡的線程都在執行任務,則進入下個流程。
  2. 線程池判斷工作隊列是否已滿。如果工作隊列沒有滿,則将新送出的任務存儲在這個工作隊列裡。如果工作隊列滿了,則進入下個流程。
  3. 線程池判斷線程池的線程是否都處于工作狀态。如果沒有,則建立一個新的工作線程來執行任務(需要獲得全局鎖)。如果已經滿了,則交給飽和政策(例如抛出異常)來處理這個任務。
tips:

這樣的設計方案,可以避免頻繁的線程建立,大部分的工作任務都會停留在第二步。

二、Executor 架構

在 Java 中,線程池的知識是要從 Executor 架構展開。Executor 架構主要由三部分組成:

1. 任務

包括 Runnable 接口或 Callable 接口。Runnable 接口無傳回值,Callable 有傳回值。

// Runnable 和 Callable 都可以直接被 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 執行
Runnable runnable = () -> System.out.println(123);
// Executors 可以将 Runnable 轉化成 Callable
Callable<Object> callable = Executors.callable(runnable);
Callable<String> success = Executors.callable(runnable, "success");
           

2. 任務的執行

包括任務執行機制的核心接口 Executor、繼承自 Executor 的 ExecutorService 接口以及實作 ExecutorService 的 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor。

ThreadPoolExecutor 是線程池的核心實作類,用來執行被送出的任務。其中 ThreadPoolExecutor 的原理就是上面介紹的線程池工作流程。

ScheduledThreadPoolExecutor 繼承自 ThreadPoolExecutor ,可以在給定的延遲後執行任務,或者定期執行任務。

Executors 是建立 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 的工廠類。

static ExecutorService executorService = Executors.newFixedThreadPool(5);
           

3. 異步計算的結果

包括 Future 接口以及實作 Future 的 FutureTask 類。

// 執行 Runnable
executorService.execute(runnable);
// 執行 Callable
Future<Object> submit = executorService.submit(callable);
// Future 的 get 方法會阻塞線程直到完成
System.out.println(submit.get());
Future<String> future = executorService.submit(success);
System.out.println(future.get());
           

當 FutureTask 處于未啟動狀态時,執行 FutureTask.cancel() 方法将導緻此任務永遠不會被執行;

當 FutureTask 處于已啟動狀态時,執行FutureTask.cancel(true)方法将以中斷執行此任務線程的方式來試圖停止任務;

當 FutureTask 處于已啟動狀态時,執行FutureTask.cancel(false)方法将不會對正在執行此任務的線程産生影響(讓正在執行的任務運作完成);

當 FutureTask 處于已完成狀态時,執行FutureTask.cancel()方法将傳回false。

Executor 線程池的使用大抵如下,首先,我們需要建立 Runnable 或者 Callable 任務。然後通過 ThreadPoolExecutor.execute() 或者 ThreadPoolExecutor.submit() 把任務交給 ThreadPoolExecutor 容器執行。由 submit 送出的任務會傳回 Future,表示線程執行的結果,其中 Future 的 get 方法會阻塞線程直到完成。

Executor架構的使用示意圖如下:

多線程程式設計學習十(線程池原理).

相關連結:10問10答:你真的了解線程池嗎?