Executors提供的四種執行緒池
Java 5+中的Executor介面定義一個執行執行緒的工具。它的子型別即執行緒池介面是ExecutorService。要配置一個執行緒池是比較複雜的,尤其是對於執行緒池的原理不是很清楚的情況下,因此在工具類Executors面提供了一些靜態工廠方法,生成一些常用的執行緒池,如下所示:
- newCachedThreadPool:建立一個可快取的執行緒池。如果執行緒池的大小超過了處理任務所需要的執行緒,那麼就會回收部分空閒(60秒不執行任務)的執行緒,當任務數增加時,此執行緒池又可以智慧的新增新執行緒來處理任務。此執行緒池不會對執行緒池大小做限制(Interger. MAX_VALUE
- newFixedThreadPool:建立固定大小的執行緒池。每次提交一個任務就建立一個執行緒,直到執行緒達到執行緒池的最大大小。執行緒池的大小一旦達到最大值就會保持不變,如果某個執行緒因為執行異常而結束,那麼執行緒池會補充一個新執行緒。
- newSingleThreadExecutor:建立一個單執行緒的執行緒池。這個執行緒池只有一個執行緒在工作,也就是相當於單執行緒序列執行所有任務。如果這個唯一的執行緒因為異常結束,那麼會有一個新的執行緒來替代它。此執行緒池保證所有任務的執行順序按照任務的提交順序執行。
- newScheduledThreadPool:建立一個大小無限的執行緒池。此執行緒池支援定時以及週期性執行任務的需求。
一、newCachedThreadPool
建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。
這種型別的執行緒池特點是:
- 工作執行緒的建立數量幾乎沒有限制 [其實也有限制的,數目為Interger. MAX_VALUE (即 2^31-1) ], 這樣可靈活的往執行緒池中新增執行緒。
- 如果長時間沒有往執行緒池中提交任務,即如果工作執行緒空閒了指定的時間(預設為1分鐘
- 在使用CachedThreadPool時,一定要注意控制任務的數量,否則,由於大量執行緒同時執行,很有會造成系統癱瘓。
public class MyCacheThreadPool { public static void main(String[] args) { //建立一個執行緒池, 大小為2^31-1 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; cachedThreadPool.execute(new Runnable() { public void run() { String currentTime = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss").format(new Date()); System.out.println(index + " currentTime=" + currentTime); } }); } } }
結果如下:
二、newFixedThreadPool
建立一個指定工作執行緒數量的執行緒池。每當提交一個任務就建立一個工作執行緒,如果工作執行緒數量達到執行緒池初始的最大數,則將提交的任務存入到池佇列中。
FixedThreadPool是一個典型且優秀的執行緒池,它具有執行緒池提高程式效率和節省建立執行緒時所耗的開銷的優點。但是,線上程池空閒時,即執行緒池中沒有可執行任務時,它不會釋放工作執行緒,還會佔用一定的系統資源。
示例程式碼如下:
public class MyFixedThreadPool { public static void main(String[] args) { //建立一個執行緒池, 大小為3; 執行緒數達到最大值後放入佇列中; 若空閒則不會釋放工作執行緒 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int index = i; fixedThreadPool.execute(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } String currentTime = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss").format(new Date()); System.out.println(index + " currentTime=" + currentTime); } }); } } }
結果如下:
因為程式碼中執行緒池的最大工作數量設定為3,則把其他多餘的執行緒存放在佇列中,同一個時間最多執行的執行緒數為3.
三、newSingleThreadExecutor
建立一個單執行緒化的Executor,即只建立唯一的工作者執行緒來執行任務,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。如果這個執行緒異常結束,會有另一個取代它,保證順序執行。單工作執行緒最大的特點是可保證順序地執行各個任務,並且在任意給定的時間不會有多個執行緒是活動的。
示例程式碼如下:
public class MySingleThreadPool { public static void main(String[] args) { //建立的執行緒池大小為1, 同一時間只執行一個執行緒, 按照提交順序來執行 ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int index = i; singleThreadPool.execute(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } String currentTime = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss").format(new Date()); System.out.println(index + " currentTime=" + currentTime); } }); } } }
執行結果:
newSingleThreadExecutor 同一個時間只執行一個執行緒,按照執行緒的提交順序執行執行緒;
四、newScheduleThreadPool
建立一個定長的執行緒池,而且支援定時的以及週期性的任務執行,支援定時及週期性任務執行。
延遲3秒執行,延遲執行示例程式碼如下:
public class MyScheduleThreadPool { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); Runnable runnable1 = new Runnable() { @Override public void run() { String currentTime = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss").format(new Date()); System.out.println("Runnable-1 currentTime=" + currentTime); } }; //延時3秒後執行 scheduledThreadPool.schedule(runnable1, 3, TimeUnit.SECONDS); Runnable runnable2 = new Runnable() { @Override public void run() { String currentTime = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss").format(new Date()); System.out.println("Runnable-2 currentTime=" + currentTime); } }; //開始延時1秒後執行, 然後每隔3秒執行一次 scheduledThreadPool.scheduleAtFixedRate(runnable2, 1, 3, TimeUnit.SECONDS); } }
結果如下: