在Java開發過程中經常需要用到線程,為了減少資源的開銷,提高系統性能,Java提供了線程池,即事先創建好線程,如果需要使用從池中取即可,Java中創建線程池有以下的方式,
1、使用ThreadPoolExecutor類
2、使用Executors類
其實這兩種方式在本質上是一種方式,都是通過ThreadPoolExecutor類的方式,下面分析其使用方式。
一、ThreadPoolExecutor的方式
1、使用方法
查看JDK的源碼,ThreadPoolExecutor類提供了以下構造方法,
可以看到有四個構造方法,先看第一個構造方法,其代碼如下,
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
從上面的代碼中可以確定,我們需要傳的參數有corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue
下面對這幾個參數進行說明
corePoolSize:線程池的核心線程數;
maximumPoolSize:線程池的最大線程數;
keepAliveTime:線程池空閑時線程的存活時長;
unit:線程存活時長大單位,結合上個參數使用;
workQueue:存放任務的隊列,使用的是阻塞隊列;
在這個方法中調用了另外的一個構造方法,即上圖中四個構造方法中的第四個,從源碼中得知,一個線程池包含的屬性共有corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler七個,上面說到了五個,下面是其他兩個的含義,
threadFactory:線程池創建線程的工廠;
handler:在隊列(workQueue)和線程池達到最大線程數(maximumPoolSize)均滿時仍有任務的情況下的處理方式;
上面的七個參數,也即ThreadPoolExecutor的第四個構造方法需要的參數。
我們再來看中間的兩個構造方法,和第一個的區別在於,第二個和第三個指定了創建線程的工廠和線程池滿時的處理策略。
通過上面的方式便創建了線程池
二、Executors的方式
1、使用方法
Executors類提供了下面的構造方法,
可以看到提供了約10個的構造方法,但是發現其方法返回值為ExecutorService,這不是我們要的ThreadPoolExecutor那,別急,看下ExecutorService這個類是什么,
其源碼如下,
其是一個接口,和ThreadPoolExecutor沒什么關系那,不對,可以大膽猜想下,ThreaPoolExecutor可以實現接口,驗證下我們的猜想,
ThreadPoolExecutor繼承了AbstractExecutorService
AbstractExecutorService抽象類實現了ExecutorService接口,那么ThreadPoolExcutor和ExecutorService就有了關系。
我們再挑選ExecutorService中的方法看下其具體實現,
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
從上面的代碼中可以看出,其返回的是ThreaPoolExecutor對象,調用的是ThreaPoolExecutor類四個構造方法中的第一個。
總結,上面兩種創建線程池的方式,其本質都是通過ThreaPoolExecutor類的構造方法的方式,所以ThreaPoolExecutor是重點。