【線程池】線程池的初始配置詳解
創(chuàng)建一個線程池
首先我們看一個創(chuàng)建線程池的例子
執(zhí)行類
public class ThreadInit {
/**
* corePoolSize - 要保留在池中的線程數(shù),即使它們處于空閑狀態(tài),除非設(shè)置了allowCoreThreadTimeOut
* maximumPoolSize - maximumPoolSize的最大線程數(shù)
* keepAliveTime - 當(dāng)線程數(shù)大于核心數(shù)時,這是多余空閑線程在終止前等待新任務(wù)的最長時間。
* unit - keepAliveTime參數(shù)的時間單位
* workQueue - 用于在執(zhí)行任務(wù)之前保存任務(wù)的隊(duì)列。 這個隊(duì)列將只保存execute方法提交的Runnable任務(wù)。
* threadFactory - 執(zhí)行程序創(chuàng)建新線程時使用的工廠
* handler - 由于達(dá)到線程邊界和隊(duì)列容量而阻塞執(zhí)行時使用的處理程序
* @param args
*/
public static void main(String[] args) {
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(10);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,5,10,TimeUnit.SECONDS,workQueue,new TestThreadFactory(),new MyRejectPolicy());
for (int i = 0; i < 20; i++) {
threadPoolExecutor.execute(()->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":執(zhí)行了");
});
}
threadPoolExecutor.shutdown();
}
}
拒絕策略類
public class MyRejectPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("被拒絕了");
}
}
線程工程類
public class TestThreadFactory implements ThreadFactory {
private static AtomicInteger atomicInteger = new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
atomicInteger.addAndGet(1);
return new Thread(r,"自定義名字-"+atomicInteger.get());
}
}
參數(shù)講解
仔細(xì)看完上面這個創(chuàng)建線程池的例子后,就會發(fā)現(xiàn),創(chuàng)建一個線程池,有六個可以配置的參數(shù),這六個參數(shù)分別是
首先我們先按順序來講解一下這六個參數(shù)的各個含義
corePoolSize
核心線程數(shù)是線程池會一直保持活躍的線程數(shù),比如我們核心線程數(shù)設(shè)置為5個線程,那么當(dāng)線程任務(wù)進(jìn)入到線程池中會始終保持有五個線程的空位使用。
maximumPoolSize
最大線程數(shù)與核心線程數(shù)還不太一樣,最大線程數(shù)是線程池再判斷線程隊(duì)列是否滿了,如果滿了則會在核心線程數(shù)的基礎(chǔ)上去創(chuàng)建新的線程,直到線程數(shù)達(dá)到了最大線程數(shù)之后變不會在創(chuàng)建。
這里有很多人都會有一個誤區(qū),把核心線程數(shù)理解為最小活躍線程,以為當(dāng)進(jìn)入到線程池后,如果超過核心線程數(shù)的任務(wù)會直接去創(chuàng)建線程執(zhí)行,直到線程數(shù)滿了之后然后在把線程存放到線程池的隊(duì)列中。其實(shí)這種理解是錯誤的,在Java的線程池中,線程池會先去判斷線程隊(duì)列有沒有滿,如果滿了,才會在核心線程數(shù)上去創(chuàng)建線程。
例如我們上面那個創(chuàng)建線程的例子來看,核心線程數(shù)為1個,最大線程數(shù)為5個,隊(duì)列最大可以存放10個。當(dāng)客戶端開始執(zhí)行20個線程的同時,核心線程會占去一個,之后的線程會先存放到線程池的隊(duì)列中,此時在隊(duì)列中存放了10個后發(fā)現(xiàn)還有9個線程需要被放入到線程池中,這是線程池就會把核心線程數(shù)擴(kuò)大到最大線程數(shù)5個。
可以參考下這個張圖片

keepAliveTime
空閑線程的存活時間代表著,如果當(dāng)我們例子中的線程池在線程數(shù)到達(dá)最大值的情況下,線程池里面的任務(wù)都執(zhí)行完了,這個時候除了1個核心線程,剩下的4個線程就會保持我們設(shè)置的keepAliveTime時間來等待,如果設(shè)置10秒后發(fā)現(xiàn)還是沒有線程進(jìn)來,這個時候這4個空閑的線程就會慢慢的關(guān)閉掉,直到下次再有線程過來,等到線程隊(duì)列滿了之后才會去創(chuàng)建這些線程。
workQueue
workQueue就是我們的線程隊(duì)列,例如我們現(xiàn)在設(shè)置的隊(duì)列BlockingQueue,他是屬于阻塞隊(duì)列,并且有最大值。這個設(shè)置需要看具體使用場景來設(shè)置,例如我們不想丟棄任何一個線程策略,就可以設(shè)置Queue,這時他就可以沒有限制的去存放你的線程任務(wù)。
threadFactory
線程工廠就比較有意思了,他可以做很多的時候,例如上面的例子中,線程工廠做了一個線程名稱的自定義,因?yàn)樵跇I(yè)務(wù)場景中,線程池中自帶默認(rèn)的創(chuàng)建線程工廠可能不太符合我們業(yè)務(wù)需求,例如自定義線程名字,線程計(jì)數(shù)等等。這種自定義的東西就可以以自己需求來判斷如何改造自己線程創(chuàng)建的方式。
handler
這個的作用是基于線程被拒絕后使用的,比如線程被拒絕后,我們想要知道被拒絕的線程有多少個,或者線程被拒絕后如何去打印被拒絕線程的日志。
總結(jié)
通過上面的參數(shù)詳解后,我們可以得出線程池的幾個特點(diǎn)和注意事項(xiàng)
- 線程池希望保持較少的線程數(shù),只有在負(fù)載變大的時候才會去擴(kuò)線程。
- 線程池只有在任務(wù)隊(duì)列填滿時才創(chuàng)建多于 corePoolSize 的線程,如果使用的是無界隊(duì)列(例如 LinkedBlockingQueue),那么由于隊(duì)列不會滿,所以線程數(shù)不會超過 corePoolSize。
- 通過設(shè)置 corePoolSize 和 maximumPoolSize 為相同的值,就可以創(chuàng)建固定大小的線程池。
- 通過設(shè)置 maximumPoolSize 為很高的值,例如 Integer.MAX_VALUE,就可以允許線程池創(chuàng)建任意多的線程。

浙公網(wǎng)安備 33010602011771號