天天看點

Java線程(六):線程池

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

        我們的web項目都是部署在伺服器上,浏覽器端的每一個request就是一個線程,那麼伺服器需要并發的處理多個請求,就需要線程池技術,下面來看一下Java并發包下如何建立線程池。

        1.  建立一個可重用固定線程集合的線程池,以共享的無界隊列方式來運作這些線程。

<code>[java]</code><code>view plaincopyprint?</code>

<code>ExecutorService threadPool = Executors.newFixedThreadPool(3);// 建立可以容納3個線程的線程池</code>

        2. 建立一個可根據需要建立新線程的線程池,但是在以前構造的線程可用時将重用它們。

<code>ExecutorService threadPool = Executors.newCachedThreadPool();// 線程池的大小會根據執行的任務數動态配置設定</code>

        3. 建立一個使用單個 worker 線程的 Executor,以無界隊列方式來運作該線程。

<code>ExecutorService threadPool = Executors.newSingleThreadExecutor();// 建立單個線程的線程池,如果目前線程在執行任務時突然中斷,則會建立一個新的線程替代它繼續執行任務</code>

        4. 建立一個可安排在給定延遲後運作指令或者定期地執行的線程池。

<code>[java]</code><code>view plaincopyprint? ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);// 效果類似于Timer定時器</code>

        每種線程池都有不同的使用場景,下面看一下這四種線程池使用起來有什麼不同。

        1. FixedThreadPool

<code>import</code><code> java.util.concurrent.ExecutorService;  </code>

<code>import</code><code> java.util.concurrent.Executors;  </code>

<code>public</code><code></code><code>class</code><code> ThreadPoolTest {  </code>

<code>public static void main(String[] args) {  </code>

<code>        ExecutorService threadPool = Executors.newFixedThreadPool(3);  </code>

<code>for(int i = 1; i &lt; 5; i++) {  </code>

<code>final int taskID = i;  </code>

<code>            threadPool.execute(new Runnable() {  </code>

<code>public void run() {  </code>

<code>try {  </code>

<code>                            Thread.sleep(20);// 為了測試出效果,讓每次任務執行都需要一定時間</code>

<code>                        } catch (InterruptedException e) {  </code>

<code>                            e.printStackTrace();  </code>

<code>                        }  </code>

<code>                        System.out.println("第" + taskID + "次任務的第" + i + "次執行");  </code>

<code>                    }  </code>

<code>                }  </code>

<code>            });  </code>

<code>        }  </code>

<code>        threadPool.shutdown();// 任務執行完畢,關閉線程池</code>

<code>    }  </code>

<code>}  </code>

        輸出結果:

<code>第1次任務的第1次執行  </code>

<code>第2次任務的第1次執行  </code>

<code>第3次任務的第1次執行  </code>

<code>第2次任務的第2次執行  </code>

<code>第3次任務的第2次執行  </code>

<code>第1次任務的第2次執行  </code>

<code>第3次任務的第3次執行  </code>

<code>第1次任務的第3次執行  </code>

<code>第2次任務的第3次執行  </code>

<code>第3次任務的第4次執行  </code>

<code>第2次任務的第4次執行  </code>

<code>第1次任務的第4次執行  </code>

<code>第4次任務的第1次執行  </code>

<code>第4次任務的第2次執行  </code>

<code>第4次任務的第3次執行  </code>

<code>第4次任務的第4次執行  </code>

        上段代碼中,建立了一個固定大小的線程池,容量為3,然後循環執行了4個任務,由輸出結果可以看到,前3個任務首先執行完,然後空閑下來的線程去執行第4個任務,在FixedThreadPool中,有一個固定大小的池,如果目前需要執行的任務超過了池大小,那麼多于的任務等待狀态,直到有空閑下來的線程執行任務,而當執行的任務小于池大小,空閑的線程也不會去銷毀。

        2. CachedThreadPool

        上段代碼其它地方不變,将newFixedThreadPool方法換成newCachedThreadPool方法。

        可見,4個任務是交替執行的,CachedThreadPool會建立一個緩存區,将初始化的線程緩存起來,如果線程有可用的,就使用之前建立好的線程,如果沒有可用的,就新建立線程,終止并且從緩存中移除已有60秒未被使用的線程。

        3. SingleThreadExecutor        

       上段代碼其它地方不變,将newFixedThreadPool方法換成newSingleThreadExecutor方法。       

輸出結果:

        4個任務是順序執行的,SingleThreadExecutor得到的是一個單個的線程,這個線程會保證你的任務執行完成,如果目前線程意外終止,會建立一個新線程繼續執行任務,這和我們直接建立線程不同,也和newFixedThreadPool(1)不同。

    4.ScheduledThreadPool

<code>import</code><code> java.util.concurrent.ScheduledExecutorService;  </code>

<code>import</code><code> java.util.concurrent.TimeUnit;  </code>

<code>        ScheduledExecutorService schedulePool = Executors.newScheduledThreadPool(1);  </code>

<code>// 5秒後執行任務</code>

<code>        schedulePool.schedule(new Runnable() {  </code>

<code>                System.out.println("爆炸");  </code>

<code>            }  </code>

<code>        }, 5, TimeUnit.SECONDS);  </code>

<code>// 5秒後執行任務,以後每2秒執行一次</code>

<code>        schedulePool.scheduleAtFixedRate(new Runnable() {  </code>

<code>@Override</code>

<code>        }, 5, 2, TimeUnit.SECONDS);  </code>

ScheduledThreadPool可以定時的或延時的執行任務。

Java的并發包很強大,上面所說隻是入門,随着學習深入,會有更多記錄在部落格裡。