1、線程池簡介:
多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。
假設一個伺服器完成一項任務所需時間為:T1 建立線程時間,T2 線上程中執行任務的時間,T3 銷毀線程時間。
如果:T1 + T3 遠大於 T2,則可以採用線程池,以提高伺服器效能。
一個線程池包括以下四個基本組成部分:
1、線程池管理器(ThreadPool):用於建立並管理線程池,包括 建立線程池,銷毀線程池,添加新任務;
2、背景工作執行緒(PoolWorker):線程池中線程,在沒有任務時處於等待狀態,可以迴圈的執行任務;
3、任務介面(Task):每個任務必須實現的介面,以供背景工作執行緒調度任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等;
4、任務隊列(taskQueue):用於存放沒有處理的任務。提供一種緩衝機制。
線程池技術正是關注如何縮短或調整T1,T3時間的技術,從而提高伺服器程式效能的。它把T1,T3分別安排在伺服器程式的啟動和結束的時間段或者一些閒置時間段,這樣在伺服器程式處理客戶請求時,不會有T1,T3的開銷了。
線程池不僅調整T1,T3產生的時間段,而且它還顯著減少了建立線程的數目,看一個例子:
假設一個伺服器一天要處理50000個請求,並且每個請求需要一個單獨的線程完成。線上程池中,線程數一般是固定的,所以產生線程總數不會超過線程池中線程的數目,而如果伺服器不利用線程池來處理這些請求則線程總數為50000。一般線程池大小是遠小於50000。所以利用線程池的伺服器程式不會為了建立50000而在處理請求時浪費時間,從而提高效率。
代碼實現中並沒有實現任務介面,而是把Runnable對象加入到線程池管理器(ThreadPool),然後剩下的事情就由線程池管理器(ThreadPool)來完成了
package mine.util.thread;import java.util.LinkedList;import java.util.List;/** * 線程池類,線程管理器:建立線程,執行任務,銷毀線程,擷取線程基本資料 */public final class ThreadPool {// 線程池中預設線程的個數為5private static int worker_num = 5;// 背景工作執行緒private WorkThread[] workThrads;// 未處理的任務private static volatile int finished_task = 0;// 任務隊列,作為一個緩衝,List線程不安全private List<Runnable> taskQueue = new LinkedList<Runnable>();private static ThreadPool threadPool;// 建立具有預設線程個數的線程池private ThreadPool() {this(5);}// 建立線程池,worker_num為線程池中背景工作執行緒的個數private ThreadPool(int worker_num) {ThreadPool.worker_num = worker_num;workThrads = new WorkThread[worker_num];for (int i = 0; i < worker_num; i++) {workThrads[i] = new WorkThread();workThrads[i].start();// 開啟線程池中的線程}}// 單態模式,獲得一個預設線程個數的線程池public static ThreadPool getThreadPool() {return getThreadPool(ThreadPool.worker_num);}// 單態模式,獲得一個指定線程個數的線程池,worker_num(>0)為線程池中背景工作執行緒的個數// worker_num<=0建立預設的背景工作執行緒個數public static ThreadPool getThreadPool(int worker_num1) {if (worker_num1 <= 0)worker_num1 = ThreadPool.worker_num;if (threadPool == null)threadPool = new ThreadPool(worker_num1);return threadPool;}// 執行任務,其實只是把任務加入任務隊列,什麼時候執行有線程池管理器覺定public void execute(Runnable task) {synchronized (taskQueue) {taskQueue.add(task);taskQueue.notify();}}// 批量執行任務,其實只是把任務加入任務隊列,什麼時候執行有線程池管理器覺定public void execute(Runnable[] task) {synchronized (taskQueue) {for (Runnable t : task)taskQueue.add(t);taskQueue.notify();}}// 批量執行任務,其實只是把任務加入任務隊列,什麼時候執行有線程池管理器覺定public void execute(List<Runnable> task) {synchronized (taskQueue) {for (Runnable t : task)taskQueue.add(t);taskQueue.notify();}}// 銷毀線程池,該方法保證在所有任務都完成的情況下才銷毀所有線程,否則等待任務完成才銷毀public void destroy() {while (!taskQueue.isEmpty()) {// 如果還有任務沒執行完成,就先睡會吧try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}// 背景工作執行緒停止工作,且置為nullfor (int i = 0; i < worker_num; i++) {workThrads[i].stopWorker();workThrads[i] = null;}threadPool=null;taskQueue.clear();// 清空任務隊列}// 返回背景工作執行緒的個數public int getWorkThreadNumber() {return worker_num;}// 返回已完成任務的個數,這裡的已完成是只出了任務隊列的任務個數,可能該任務並沒有實際執行完成public int getFinishedTasknumber() {return finished_task;}// 返回任務隊列的長度,即還沒處理的任務個數public int getWaitTasknumber() {return taskQueue.size();}// 覆蓋toString方法,返回線程池資訊:背景工作執行緒個數和已完成任務個數@Overridepublic String toString() {return "WorkThread number:" + worker_num + " finished task number:"+ finished_task + " wait task number:" + getWaitTasknumber();}/** * 內部類,背景工作執行緒 */private class WorkThread extends Thread {// 該背景工作執行緒是否有效,用於結束該背景工作執行緒private boolean isRunning = true;/* * 關鍵所在啊,如果任務隊列不空,則取出任務執行,若任務隊列空,則等待 */@Overridepublic void run() {Runnable r = null;while (isRunning) {// 注意,若線程無效則自然結束run方法,該線程就沒用了synchronized (taskQueue) {while (isRunning && taskQueue.isEmpty()) {// 隊列為空白try {taskQueue.wait(20);} catch (InterruptedException e) {e.printStackTrace();}}if (!taskQueue.isEmpty())r = taskQueue.remove(0);// 取出任務}if (r != null) {r.run();// 執行任務}finished_task++;r = null;}}// 停止工作,讓該線程自然執行完run方法,自然結束public void stopWorker() {isRunning = false;}}}
測試代碼:
package mine.util.thread;//測試線程池public class TestThreadPool {public static void main(String[] args) {// 建立3個線程的線程池ThreadPool t = ThreadPool.getThreadPool(3);t.execute(new Runnable[] { new Task(), new Task(), new Task() });t.execute(new Runnable[] { new Task(), new Task(), new Task() });System.out.println(t);t.destroy();// 所有線程都執行完成才destorySystem.out.println(t);}// 任務類static class Task implements Runnable {private static volatile int i = 1;@Overridepublic void run() {// 執行任務System.out.println("任務 " + (i++) + " 完成");}}}
運行結果:
WorkThread number:3 finished task number:0 wait task number:6
任務 1 完成
任務 2 完成
任務 3 完成
任務 4 完成
任務 5 完成
任務 6 完成
WorkThread number:3 finished task number:6 wait task number:0
分析:由於並沒有任務介面,傳入的可以是自訂的任何任務,所以線程池並不能準確的判斷該任務是否真正的已經完成(真正完成該任務是這個任務的run方法執行完畢),只能知道該任務已經出了任務隊列,正在執行或者已經完成。
2、java類庫中提供的線程池簡介:
java提供的線程池更加強大,相信理解線程池的工作原理,看類庫中的線程池就不會感到陌生了。
其他具體內容查看jdk協助或看jdk原始碼吧。。。
參考文章:http://hi.baidu.com/obullxl/blog/item/ee50ad1ba8e8ff1f8718bf66.html