1. 程式人生 > >Java執行緒(六):執行緒池

Java執行緒(六):執行緒池

        自JDK5之後,Java推出了一個併發包,java.util.concurrent,在Java開發中,我們接觸到了好多池的技術,String類的物件池、Integer的共享池、連線資料庫的連線池、Struts1.3的物件池等等,池的最終目的都是節約資源,以更小的開銷做更多的事情,從而提高效能。

        我們的web專案都是部署在伺服器上,瀏覽器端的每一個request就是一個執行緒,那麼伺服器需要併發的處理多個請求,就需要執行緒池技術,下面來看一下Java併發包下如何建立執行緒池。

        1.  建立一個可重用固定執行緒集合的執行緒池,以共享的無界佇列方式來執行這些執行緒。

[java] view plaincopyprint?
  1. ExecutorService threadPool = Executors.newFixedThreadPool(3);// 建立可以容納3個執行緒的執行緒池
        2. 建立一個可根據需要建立新執行緒的執行緒池,但是在以前構造的執行緒可用時將重用它們。[java] view plaincopyprint?
  1. ExecutorService threadPool = Executors.newCachedThreadPool();// 執行緒池的大小會根據執行的任務數動態分配
        3. 建立一個使用單個 worker 執行緒的 Executor,以無界佇列方式來執行該執行緒。
[java] view plaincopyprint?
  1. ExecutorService threadPool = Executors.newSingleThreadExecutor();// 建立單個執行緒的執行緒池,如果當前執行緒在執行任務時突然中斷,則會建立一個新的執行緒替代它繼續執行任務
        4. 建立一個可安排在給定延遲後執行命令或者定期地執行的執行緒池。[java] view plaincopyprint?
  1. ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);// 效果類似於Timer定時器
        每種執行緒池都有不同的使用場景,下面看一下這四種執行緒池使用起來有什麼不同。

        1. FixedThreadPool

[java] view plaincopyprint?
  1. import java.util.concurrent.ExecutorService;  
  2. import java.util.concurrent.Executors;  
  3. publicclass ThreadPoolTest {  
  4.     publicstaticvoid main(String[] args) {  
  5.         ExecutorService threadPool = Executors.newFixedThreadPool(3);  
  6.         for(int i = 1; i < 5; i++) {  
  7.             finalint taskID = i;  
  8.             threadPool.execute(new Runnable() {  
  9.                 publicvoid 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. }  
        輸出結果:[java] view plaincopyprint?
  1. 1次任務的第1次執行  
  2. 2次任務的第1次執行  
  3. 3次任務的第1次執行  
  4. 2次任務的第2次執行  
  5. 3次任務的第2次執行  
  6. 1次任務的第2次執行  
  7. 3次任務的第3次執行  
  8. 1次任務的第3次執行  
  9. 2次任務的第3次執行  
  10. 3次任務的第4次執行  
  11. 2次任務的第4次執行  
  12. 1次任務的第4次執行  
  13. 4次任務的第1次執行  
  14. 4次任務的第2次執行  
  15. 4次任務的第3次執行  
  16. 4次任務的第4次執行  
        上段程式碼中,建立了一個固定大小的執行緒池,容量為3,然後迴圈執行了4個任務,由輸出結果可以看到,前3個任務首先執行完,然後空閒下來的執行緒去執行第4個任務,在FixedThreadPool中,有一個固定大小的池,如果當前需要執行的任務超過了池大小,那麼多於的任務等待狀態,直到有空閒下來的執行緒執行任務,而當執行的任務小於池大小,空閒的執行緒也不會去銷燬。
        2. CachedThreadPool

        上段程式碼其它地方不變,將newFixedThreadPool方法換成newCachedThreadPool方法。

        輸出結果:

[java] view plaincopyprint?
  1. 3次任務的第1次執行  
  2. 4次任務的第1次執行  
  3. 1次任務的第1次執行  
  4. 2次任務的第1次執行  
  5. 4次任務的第2次執行  
  6. 3次任務的第2次執行  
  7. 2次任務的第2次執行  
  8. 1次任務的第2次執行  
  9. 2次任務的第3次執行  
  10. 3次任務的第3次執行  
  11. 1次任務的第3次執行  
  12. 4次任務的第3次執行  
  13. 2次任務的第4次執行  
  14. 4次任務的第4次執行  
  15. 3次任務的第4次執行  
  16. 1次任務的第4次執行  
        可見,4個任務是交替執行的,CachedThreadPool會建立一個快取區,將初始化的執行緒快取起來,如果執行緒有可用的,就使用之前建立好的執行緒,如果沒有可用的,就新建立執行緒,終止並且從快取中移除已有60秒未被使用的執行緒。

        3. SingleThreadExecutor        

       上段程式碼其它地方不變,將newFixedThreadPool方法換成newSingleThreadExecutor方法。       

輸出結果:

[java] view plaincopyprint?
  1. 1次任務的第1次執行  
  2. 1次任務的第2次執行  
  3. 1次任務的第3次執行  
  4. 1次任務的第4次執行  
  5. 2次任務的第1次執行  
  6. 2次任務的第2次執行  
  7. 2次任務的第3次執行  
  8. 2次任務的第4次執行  
  9. 3次任務的第1次執行  
  10. 3次任務的第2次執行  
  11. 3次任務的第3次執行  
  12. 3次任務的第4次執行  
  13. 4次任務的第1次執行  
  14. 4次任務的第2次執行  
  15. 4次任務的第3次執行  
  16. 4次任務的第4次執行  
        4個任務是順序執行的,SingleThreadExecutor得到的是一個單個的執行緒,這個執行緒會保證你的任務執行完成,如果當前執行緒意外終止,會建立一個新執行緒繼續執行任務,這和我們直接建立執行緒不同,也和newFixedThreadPool(1)不同。

    4.ScheduledThreadPool

[java] view plaincopyprint?
  1. import java.util.concurrent.ScheduledExecutorService;  
  2. import java.util.concurrent.TimeUnit;  
  3. publicclass ThreadPoolTest {  
  4.     publicstaticvoid main(String[] args) {  
  5.         ScheduledExecutorService schedulePool = Executors.newScheduledThreadPool(1);  
  6.         // 5秒後執行任務
  7.         schedulePool.schedule(new Runnable() {  
  8.             publicvoid run() {  
  9.                 System.out.println("爆炸");  
  10.             }  
  11.         }, 5, TimeUnit.SECONDS);  
  12.         // 5秒後執行任務,以後每2秒執行一次
  13.         schedulePool.scheduleAtFixedRate(new Runnable() {  
  14.             @Override
  15.             publicvoid run() {  
  16.                 System.out.println("爆炸");  
  17.             }  
  18.         }, 52, TimeUnit.SECONDS);  
  19.     }  
  20. }  
ScheduledThreadPool可以定時的或延時的執行任務。

Java的併發包很強大,上面所說只是入門,隨著學習深入,會有更多記錄在部落格裡。