為什么用線程池
有時候,系統(tǒng)需要處理非常多的執(zhí)行時間很短的請求,如果每一個請求都開啟一個新線程的話,系統(tǒng)就要不斷的進(jìn)行線程的創(chuàng)建和銷毀,有時花在創(chuàng)建和銷毀線程上的時間會比線程真正執(zhí)行的時間還長。而且當(dāng)線程數(shù)量太多時,系統(tǒng)不一定能受得了。
使用線程池主要為了解決一下幾個問題:
- 通過重用線程池中的線程,來減少每個線程創(chuàng)建和銷毀的性能開銷。
- 對線程進(jìn)行一些維護(hù)和管理,比如定時開始,周期執(zhí)行,并發(fā)數(shù)控制等等。
Executor
注意:不同于Executors(類)
Executor是一個接口,跟線程池有關(guān)的基本都要跟他打交道。下面是常用的ThreadPoolExecutor的關(guān)系。
線程池規(guī)則驗證
下面都假設(shè)任務(wù)隊列沒有大小限制
- 如果線程數(shù)量<=核心線程數(shù)量,那么直接啟動一個核心線程來執(zhí)行任務(wù),不會放入隊列中。
- 如果線程數(shù)量>核心線程數(shù),但<=最大線程數(shù),并且任務(wù)隊列是LinkedBlockingDeque的時候,超過核心線程數(shù)量的任務(wù)會放在任務(wù)隊列中排隊。
- 如果線程數(shù)量>核心線程數(shù),但<=最大線程數(shù),并且任務(wù)隊列是SynchronousQueue的時候,線程池會創(chuàng)建新線程執(zhí)行任務(wù),這些任務(wù)也不會被放在任務(wù)隊列中。這些線程屬于非核心線程,在任務(wù)完成后,閑置時間達(dá)到了超時時間就會被清除。
- 如果線程數(shù)量>核心線程數(shù),并且>最大線程數(shù),當(dāng)任務(wù)隊列是LinkedBlockingDeque,會將超過核心線程的任務(wù)放在任務(wù)隊列中排隊。也就是當(dāng)任務(wù)隊列是LinkedBlockingDeque并且沒有大小限制時,線程池的最大線程數(shù)設(shè)置是無效的,他的線程數(shù)最多不會超過核心線程數(shù)。
- 如果線程數(shù)量>核心線程數(shù),并且>最大線程數(shù),當(dāng)任務(wù)隊列是SynchronousQueue的時候,會因為線程池拒絕添加任務(wù)而拋出異常。
任務(wù)隊列大小有限時
- 當(dāng)LinkedBlockingDeque塞滿時,新增的任務(wù)會直接創(chuàng)建新線程來執(zhí)行,當(dāng)創(chuàng)建的線程數(shù)量超過最大線程數(shù)量時會拋異常。
- SynchronousQueue沒有數(shù)量限制。因為他根本不保持這些任務(wù),而是直接交給線程池去執(zhí)行。當(dāng)任務(wù)數(shù)量超過最大線程數(shù)時會直接拋異常。
圖:

image.png
代碼驗證
所有任務(wù)
/**
* 所有的任務(wù)
*/
Runnable runnable = new Runnable() {
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "is runing....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
驗證示例
ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 10, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
executor.execute(runnable);
executor.execute(runnable);
executor.execute(runnable);
System.out.println("---先開三個---");
System.out.println("核心線程數(shù):" + executor.getCorePoolSize());
System.out.println("線程池數(shù):" + executor.getPoolSize());
System.out.println("隊列任務(wù)數(shù)" + executor.getQueue().size());
executor.execute(runnable);
executor.execute(runnable);
executor.execute(runnable);
System.out.println("---再開三個---");
System.out.println("核心線程數(shù):" + executor.getCorePoolSize());
System.out.println("線程池數(shù):" + executor.getPoolSize());
System.out.println("隊列任務(wù)數(shù)" + executor.getQueue().size());
Thread.sleep(8000);
System.out.println("---8秒之后再來三個---");
System.out.println("核心線程數(shù):" + executor.getCorePoolSize());
System.out.println("線程池數(shù):" + executor.getPoolSize());
System.out.println("隊列任務(wù)數(shù)" + executor.getQueue().size());