標籤:
自JDK5之後,Java推出了一個並發包,java.util.concurrent,在Java開發中,我們接觸到了好多池的技術,String類的對象池、Integer的共用池、串連資料庫的串連池、Struts1.3的對象池等等,池的最終目的都是節約資源,以更小的開銷做更多的事情,從而提高效能。
我們的web項目都是部署在伺服器上,瀏覽器端的每一個request就是一個線程,那麼伺服器需要並發的處理多個請求,就需要線程池技術,下面來看一下Java並發包下如何建立線程池。
1. 建立一個可重用固定線程集合的線程池,以共用的無界隊列方式來運行這些線程。
1 ExecutorService threadPool = Executors.newFixedThreadPool(3);// 建立可以容納3個線程的線程池
2. 建立一個可根據需要建立新線程的線程池,但是在以前構造的線程可用時將重用它們。
1 ExecutorService threadPool = Executors.newCachedThreadPool();// 線程池的大小會根據執行的任務數動態分配
3. 建立一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。
1 ExecutorService threadPool = Executors.newSingleThreadExecutor();// 建立單個線程的線程池,如果當前線程在執行任務時突然中斷,則會建立一個新的線程替代它繼續執行任務
4. 建立一個可安排在給定延遲後運行命令或者定期地執行的線程池。
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);// 效果類似於Timer定時器
每種線程池都有不同的使用情境,下面看一下這四種線程池使用起來有什麼不同。
1. FixedThreadPool
1 import java.util.concurrent.ExecutorService; 2 import java.util.concurrent.Executors; 3 public class ThreadPoolTest { 4 public static void main(String[] args) { 5 ExecutorService threadPool = Executors.newFixedThreadPool(3); 6 for(int i = 1; i < 5; i++) { 7 final int taskID = i; 8 threadPool.execute(new Runnable() { 9 public void run() { 10 for(int i = 1; i < 5; i++) { 11 try { 12 Thread.sleep(20);// 為了測試出效果,讓每次任務執行都需要一定時間 13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 } 16 System.out.println("第" + taskID + "次任務的第" + i + "次執行"); 17 } 18 } 19 }); 20 } 21 threadPool.shutdown();// 任務執行完畢,關閉線程池 22 } 23 }
輸出結果:
- 第1次任務的第1次執行
- 第2次任務的第1次執行
- 第3次任務的第1次執行
- 第2次任務的第2次執行
- 第3次任務的第2次執行
- 第1次任務的第2次執行
- 第3次任務的第3次執行
- 第1次任務的第3次執行
- 第2次任務的第3次執行
- 第3次任務的第4次執行
- 第2次任務的第4次執行
- 第1次任務的第4次執行
- 第4次任務的第1次執行
- 第4次任務的第2次執行
- 第4次任務的第3次執行
- 第4次任務的第4次執行
上段代碼中,建立了一個固定大小的線程池,容量為3,然後迴圈執行了4個任務,由輸出結果可以看到,前3個任務首先執行完,然後空閑下來的線程去執行第4個任務,在FixedThreadPool中,有一個固定大小的池,如果當前需要執行的任務超過了池大小,那麼多於的任務等待狀態,直到有空閑下來的線程執行任務,而當執行的任務小於池大小,閒置線程也不會去銷毀。
2. CachedThreadPool
上段代碼其它地方不變,將newFixedThreadPool方法換成newCachedThreadPool方法。
輸出結果:
- 第3次任務的第1次執行
- 第4次任務的第1次執行
- 第1次任務的第1次執行
- 第2次任務的第1次執行
- 第4次任務的第2次執行
- 第3次任務的第2次執行
- 第2次任務的第2次執行
- 第1次任務的第2次執行
- 第2次任務的第3次執行
- 第3次任務的第3次執行
- 第1次任務的第3次執行
- 第4次任務的第3次執行
- 第2次任務的第4次執行
- 第4次任務的第4次執行
- 第3次任務的第4次執行
- 第1次任務的第4次執行
可見,4個任務是交替執行的,CachedThreadPool會建立一個緩衝區,將初始化的線程緩衝起來,如果線程有可用的,就使用之前建立好的線程,如果沒有可用的,就新建立線程,終止並且從緩衝中移除已有60秒未被使用的線程。
3. SingleThreadExecutor
上段代碼其它地方不變,將newFixedThreadPool方法換成newSingleThreadExecutor方法。
輸出結果:
- 第1次任務的第1次執行
- 第1次任務的第2次執行
- 第1次任務的第3次執行
- 第1次任務的第4次執行
- 第2次任務的第1次執行
- 第2次任務的第2次執行
- 第2次任務的第3次執行
- 第2次任務的第4次執行
- 第3次任務的第1次執行
- 第3次任務的第2次執行
- 第3次任務的第3次執行
- 第3次任務的第4次執行
- 第4次任務的第1次執行
- 第4次任務的第2次執行
- 第4次任務的第3次執行
- 第4次任務的第4次執行
4個任務是順序執行的,SingleThreadExecutor得到的是一個單個的線程,這個線程會保證你的任務執行完成,如果當前線程意外終止,會建立一個新線程繼續執行任務,這和我們直接建立線程不同,也和newFixedThreadPool(1)不同。
4.ScheduledThreadPool
1 import java.util.concurrent.ScheduledExecutorService; 2 import java.util.concurrent.TimeUnit; 3 public class ThreadPoolTest { 4 public static void main(String[] args) { 5 ScheduledExecutorService schedulePool = Executors.newScheduledThreadPool(1); 6 // 5秒後執行任務 7 schedulePool.schedule(new Runnable() { 8 public void run() { 9 System.out.println("爆炸"); 10 } 11 }, 5, TimeUnit.SECONDS); 12 // 5秒後執行任務,以後每2秒執行一次 13 schedulePool.scheduleAtFixedRate(new Runnable() { 14 @Override 15 public void run() { 16 System.out.println("爆炸"); 17 } 18 }, 5, 2, TimeUnit.SECONDS); 19 } 20 }
ScheduledThreadPool可以定時的或延時的執行任務。
Java的並發包很強大,上面所說只是入門,隨著學習深入,會有更多記錄在部落格裡。
本文來自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7443324,轉載請註明。
java多線程之線程池