線程池(Thread Pool)對於限制應用程序中同一時刻運行的線程數很有用。因爲每啓動一個新線程都會有相應的性能開銷,每個線程都需要給棧分配一些內存等等。
我們可以把併發執行的任務傳遞給一個線程池,來替代爲每個併發執行的任務都啓動一個新的線程。只要池裏有空閒的線程,任務就會分配給一個線程執行。在線程池的內部,任務被插入一個阻塞隊列(Blocking Queue ),線程池裏的線程會去取這個隊列裏的任務。當一個新任務插入隊列時,一個空閒線程就會成功的從隊列中取出任務並且執行它。
線程池經常應用在多線程服務器上。每個通過網絡到達服務器的連接都被包裝成一個任務並且傳遞給線程池。線程池的線程會併發的處理連接上的請求。以後會再深入有關 Java 實現多線程服務器的細節。
Java 5 在 java.util.concurrent
包中自帶了內置的線程池,所以你不用非得實現自己的線程池。你可以閱讀我寫的 java.util.concurrent.ExecutorService 的文章以瞭解更多有關內置線程池的知識。不過無論如何,知道一點關於線程池實現的知識總是有用的。
這裏有一個簡單的線程池實現:
01 |
public class ThreadPool
{ |
03 |
private BlockingQueue
taskQueue = null ; |
04 |
private List<PoolThread>
threads = new ArrayList<PoolThread>(); |
05 |
private boolean isStopped
= false ; |
07 |
public ThreadPool( int noOfThreads, int maxNoOfTasks)
{ |
08 |
taskQueue
= new BlockingQueue(maxNoOfTasks); |
10 |
for ( int i= 0 ;
i<noOfThreads; i++) { |
11 |
threads.add( new PoolThread(taskQueue)); |
13 |
for (PoolThread
thread : threads) { |
18 |
public void synchronized execute(Runnable
task) { |
19 |
if ( this .isStopped) throw |
20 |
new IllegalStateException( "ThreadPool
is stopped" ); |
22 |
this .taskQueue.enqueue(task); |
25 |
public synchronized boolean stop()
{ |
26 |
this .isStopped
= true ; |
27 |
for (PoolThread
thread : threads) { |
(校注:原文有編譯錯誤,我修改了下)
01 |
public class PoolThread extends Thread
{ |
03 |
private BlockingQueue<Runnable>
taskQueue = null ; |
04 |
private boolean
isStopped
= false ; |
06 |
public PoolThread(BlockingQueue<Runnable>
queue) { |
11 |
while (!isStopped())
{ |
13 |
Runnable
runnable =taskQueue.take(); |
15 |
} catch (Exception
e) { |
22 |
public synchronized void toStop()
{ |
27 |
public synchronized boolean isStopped()
{ |
線程池的實現由兩部分組成。類 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()
方法退出,子線程終止。