線程池參數解析以及送出任務的流程
- 線程池的 6 個參數
- 線程池處理新送出的任務
線程池的好處
- 降低資源消耗:通過重複利用已建立的線程降低線程建立和銷毀造成的消耗。
- 提高響應速度:當任務到達時,任務可以不需要等到線程建立就能立即執行。
- 提高線程的可管理性:線程是稀缺資源,如果無限制地建立,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一配置設定、調優和監控。
線程池的 6 個參數
ThreadPoolExecutor(Executor 接口的實作類)提供的構造方法:
ThreadPoolExecutor有以下四個構造方法
-
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
-
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, -BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
-
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)
-
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
1
corePoolSize
(線程池的基本大小):當送出一個任務到線程池時,線程池會建立一個線程來執行任務,即使其他空閑的基本線程能夠執行新任務也會建立線程,等到需要執行的任務數大于線程池基本大小時就不再建立。如果調用了prestartAllCoreThreads()方法,線程池會提前建立并啟動所有基本線程。
2
workQueue(任務隊列)
: 用于儲存等待執行的任務的阻塞隊列。可以選擇以下幾個阻塞隊列:
- ArrayBlockingQueue:是一個基于數組結構的有界阻塞隊列,按FIFO原則進行排序
- LinkedBlockingQueue:一個基于連結清單結構的阻塞隊列,吞吐量高于ArrayBlockingQueue。靜态工廠方法Excutors.newFixedThreadPool()使用了這個隊列
- SynchronousQueue: 一個不存儲元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處于阻塞狀态,吞吐量高于LinkedBlockingQueue,靜态工廠方法Excutors.newCachedThreadPool()使用了這個隊列
-
PriorityBlockingQueue:一個具有優先級的無限阻塞隊列。
3
maximumPoolSize(線程池最大數量)
:線程池允許建立的最大線程數。如果隊列滿了,并且已建立的線程數小于最大線程數,則線程池會再建立新的線程執行任務。值得注意的是,如果使用了無界的任務隊列這個參數就沒用了。
4
threadFactory(線程工廠)
:可以通過線程工廠為每個建立出來的線程設定更有意義的名字,如開源架構guava
5
:當隊列和線程池都滿了,說明線程池處于飽和狀态,那麼必須采取一種政策還處理新送出的任務。它可以有如下四個選項:RejectedExecutionHandler (飽和政策)
- AbortPolicy:直接抛出異常,預設情況下采用這種政策
- CallerRunsPolicy:隻用調用者所線上程來運作任務
- DiscardOldestPolicy:丢棄隊列裡最近的一個任務,并執行目前任務
-
DiscardPolicy:不處理,丢棄掉
更多的時候,我們應該通過實作RejectedExecutionHandler 接口來自定義政策,比如記錄日志或持久化存儲等。
6
:線程池的工作線程空閑後,保持存活的時間。是以如果任務很多,并且每個任務執行的時間比較短,可以調大時間,提高線程使用率。keepAliveTime(線程活動時間)
7
TimeUnit(線程活動時間的機關)
:可選的機關有天(Days)、小時(HOURS)、分鐘(MINUTES)、毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之一毫秒)和納秒(NANOSECONDS,千分之一微秒)。
線程池處理新送出的任務
當一個任務送出到線程池,線程池的處理流程:
總結:任務進來之後,線程池會逐一判斷 corePoolSize 、workQueue 、maxPoolSize ,如果依然不能滿足需求,則會拒絕任務。
有兩種方法向線程池送出任務:
可以使用execute和submit兩個方法向線程池送出任務
-
execute方法用于送出不需要傳回值的任務,利用這種方式送出的任務無法得知是否正常執行
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Future<?> future=threadPoolExecutor.submit(futureTask);
Object value=future.get();