線程池的好處
1、線程的創建需要消耗的,用完了馬上就扔了比較可惜,所以把它緩存起來,以后還能再用;
2、可以根據實際情況調整線程池的大小,防止線程太多;
3、有些場合可以用線程池來做同步(比如多個線程使用同一文件系統時,可以用SingleThreadExecutor來保持同步);
可緩存(可變大小)的線程池 CachedThreadPool
這是一種很寬松的線程池,當任務來了之后,如果沒有可用的線程那么就新建一個,如果有空閑的線程,則直接使用現有的線程。
可以根據實際的處理需求動態變化線程的數量。如果實際處理需求沒那么多了,就會把部分線程回收掉。反之,如果實際處理需求又上來了,就會重新創建線程。
比如下面的代碼,模擬每隔2秒才有一個新任務,而這個任務每次只需要1秒就能執行完:
public class CachedThreadPool { static Random random = new Random(); static int taskId = 0; static ExecutorService service = Executors.newCachedThreadPool(); public static void main(String[] args) { while(true) { service.execute(new MyThread()); try { //新增任務速度 Thread.sleep(new Long(2*1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } static class MyThread implements Runnable{ @Override public void run() { System.out.println("thread " + Thread.currentThread().getName() + " is running for task:" + (taskId++)); try { //任務線程執行所需時間 Thread.sleep(new Long(1*1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
這種情況下,線程池只需要一個線程就夠用了:
thread pool-1-thread-1 is running for task:0 thread pool-1-thread-1 is running for task:1 thread pool-1-thread-1 is running for task:2 thread pool-1-thread-1 is running for task:3 thread pool-1-thread-1 is running for task:4 thread pool-1-thread-1 is running for task:5
如果把任務執行時間增加到3秒,則會產生3個線程:
thread pool-1-thread-1 is running for task:0 thread pool-1-thread-2 is running for task:1 thread pool-1-thread-3 is running for task:2 thread pool-1-thread-1 is running for task:3 thread pool-1-thread-2 is running for task:4 thread pool-1-thread-3 is running for task:5 thread pool-1-thread-1 is running for task:6 thread pool-1-thread-2 is running for task:7 thread pool-1-thread-3 is running for task:8 thread pool-1-thread-1 is running for task:9
如果剛開始新增任務速度很快,后來變慢了,之前新增的線程會被回收掉:
public static void main(String[] args) { int i = 0; while(true) { service.execute(new MyThread()); long sleep = i>=5 ? 2000 : 50; #<---------------- 前五個任務新增得很快故意讓線程池多創建任務,之后變慢,讓增加速度比任務執行速度還慢 try { //新增任務速度 Thread.sleep(sleep); } catch (InterruptedException e) { e.printStackTrace(); } i++; } } static class MyThread implements Runnable{ @Override public void run() { System.out.println("thread " + Thread.currentThread().getName() + " is running for task:" + (taskId++)); try { //任務線程執行所需時間 Thread.sleep(new Long(1*1000)); #<-------------------- 執行速度是1秒,新增速度的一半 } catch (InterruptedException e) { e.printStackTrace(); } } }
輸出結果如下:
thread pool-1-thread-1 is running for task:0 thread pool-1-thread-2 is running for task:1 thread pool-1-thread-3 is running for task:2 thread pool-1-thread-4 is running for task:3 thread pool-1-thread-5 is running for task:4 thread pool-1-thread-6 is running for task:5 thread pool-1-thread-6 is running for task:6 thread pool-1-thread-6 is running for task:7 thread pool-1-thread-6 is running for task:8 thread pool-1-thread-6 is running for task:9 thread pool-1-thread-6 is running for task:10 thread pool-1-thread-6 is running for task:11 thread pool-1-thread-6 is running for task:12 ...
后面只有thread-6在跑了,打開jconsole,會發現其他的thread-1-threac-X已經不見了。

固定大小的線程池 FixedThreadPool
這個好理解了,我就這么幾個線程,你任務再多也沒用。
定時執行線程池 ScheduledThreadPool
定時任務線程池要注意的是,在線程資源稀缺的時候(就是線程數量設置的很小,比增加的定時任務還少,不夠用),任務的執行時間會影響任務的執行周期。簡單來說就是不要把線程數量設置的太少了。
單線程的線程池 SingleThreadExecutor
它創建單個工作者來執行任務,如果工作者線程異常退出了會重新創建一個來替換。它可以確保任務在隊列中依次串行執行,例如FIFO、LIFO、優先級。另外固定大小的線程池還提供了大量同步機制,從而是一個任務寫入到內存的結果對於后續的任務是可見的。
