標籤:java 線程池 多線程
文地址:jenkov Jakob Jenkov 譯者:長源 校對:方騰飛
java線程池(Thread Pool)對於限制應用程式中同一時刻啟動並執行線程數很有用。因為每啟動一個新線程都會有相應的效能開銷,每個線程都需要給棧分配一些記憶體等等。
我們可以把並發執行的任務傳遞給一個線程池,來替代為每個並發執行的任務都啟動一個新的線程。只要池裡有閒置線程,任務就會分配給一個線程執行。線上程池的內部,任務被插入一個阻塞隊列(Blocking Queue ),線程池裡的線程會去取這個隊列裡的任務。當一個新任務插入隊列時,一個空閑線程就會成功的從隊列中取出任務並且執行它。
線程池經常應用在多線程伺服器上。每個通過網路到達伺服器的串連都被封裝成一個任務並且傳遞給線程池。線程池的線程會並發的處理串連上的請求。以後會再深入有關 Java 實現多線程伺服器的細節。
Java 5 在 java.util.concurrent 包中內建了內建的線程池,所以你不用非得實現自己的線程池。你可以閱讀我寫的 java.util.concurrent.ExecutorService 的文章以瞭解更多有關內建線程池的知識。不過無論如何,知道一點關於線程池實現的知識總是有用的。
這裡有一個簡單的線程池實現:
public class ThreadPool {
private BlockingQueue taskQueue = null;
private List<PoolThread> threads = new ArrayList<PoolThread>();
private boolean isStopped = false;
public ThreadPool(int noOfThreads, int maxNoOfTasks) {
taskQueue = new BlockingQueue(maxNoOfTasks);
for (int i=0; i<noOfThreads; i++) {
threads.add(new PoolThread(taskQueue));
}
for (PoolThread thread : threads) {
thread.start();
}
}
public void synchronized execute(Runnable task) {
if(this.isStopped) throw
new IllegalStateException("ThreadPool is stopped");
this.taskQueue.enqueue(task);
}
public synchronized boolean stop() {
this.isStopped = true;
for (PoolThread thread : threads) {
thread.stop();
}
}
}
複製代碼
<span style="color: rgb(102, 102, 102); font-family: Arial, Helvetica, sans-serif; line-height: 35px; widows: auto; background-color: rgb(255, 255, 255);">(校註:原文有編譯錯誤,我修改了下)</span>
複製代碼
線程池的實現由兩部分組成。類 ThreadPool 是線程池的公開介面,而類 PoolThread 用來實現執行任務的子線程。
為了執行一個任務,方法 ThreadPool.execute(Runnable r) 用 Runnable 的實現作為調用參數。在內部,Runnable 對象被放入 阻塞隊列 (Blocking Queue),等待著被子線程取出隊列。
一個閒置 PoolThread 線程會把 Runnable 對象從隊列中取出並執行。你可以在 PoolThread.run() 方法裡看到這些代碼。執行完畢後,PoolThread 進入迴圈並且嘗試從隊列中再取出一個任務,直到線程終止。
調用 ThreadPool.stop() 方法可以停止 ThreadPool。在內部,調用 stop 先會標記 isStopped 成員變數(為 true)。然後,線程池的每一個子線程都調用 PoolThread.stop() 方法停止運行。注意,如果線程池的 execute() 在 stop() 之後調用,execute() 方法會拋出 IllegalStateException 異常。
子線程會在完成當前執行的任務後停止。注意 PoolThread.stop() 方法中調用了 this.interrupt()。它確保阻塞在 taskQueue.dequeue() 裡的 wait() 調用的線程能夠跳出 wait() 調用(校對註:因為執行了中斷interrupt,它能夠打斷這個調用),並且拋出一個 InterruptedException 異常離開 dequeue() 方法。這個異常在PoolThread.run() 方法中被截獲、報告,然後再檢查 isStopped 變數。由於 isStopped 的值是 true, 因此PoolThread.run() 方法退出,子線程終止。
JAVA線程池