線程池(Thread Pool)對於限制應用程式中同一時刻運行的線程數很有用。因為每啟動一個新線程都會有相應的性能開銷,每個線程都需要給棧分配一些記憶體等等。 我們可以把併發執行的任務傳遞給一個線程池,來替代為每個併發執行的任務都啟動一個新的線程。只要池裡有空閑的線程,任務就會分配給一個線程執行。線上 ...
線程池(Thread Pool)對於限制應用程式中同一時刻運行的線程數很有用。因為每啟動一個新線程都會有相應的性能開銷,每個線程都需要給棧分配一些記憶體等等。
我們可以把併發執行的任務傳遞給一個線程池,來替代為每個併發執行的任務都啟動一個新的線程。只要池裡有空閑的線程,任務就會分配給一個線程執行。線上程池的內部,任務被插入一個阻塞隊列(Blocking Queue),線程池裡的線程會去取這個隊列里的任務。當一個新任務插入隊列時,一個空閑線程就會成功的從隊列中取出任務並且執行它。
線程池經常應用在多線程伺服器上。每個通過網路到達伺服器的連接都被包裝成一個任務並且傳遞給線程池。線程池的線程會併發的處理連接上的請求。以後會再深入有關 Java 實現多線程伺服器的細節。
Java 5 在 java.util.concurrent 包中自帶了內置的線程池,所以你不用非得實現自己的線程池。
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(); } } }
線程池的實現由兩部分組成。類 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()方法退出,子線程終止。