天天看點

線程池的原理及實作(轉)

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 {  

    // 線程池中預設線程的個數為5  

    private 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) {  

            for (Runnable t : task)  

                taskQueue.add(t);  

    public void execute(List<Runnable> task) {  

    // 銷毀線程池,該方法保證在所有任務都完成的情況下才銷毀所有線程,否則等待任務完成才銷毀  

    public void destroy() {  

        while (!taskQueue.isEmpty()) {// 如果還有任務沒執行完成,就先睡會吧  

            try {  

                Thread.sleep(10);  

            } catch (InterruptedException e) {  

                e.printStackTrace();  

            }  

        // 工作線程停止工作,且置為null  

            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方法,傳回線程池資訊:工作線程個數和已完成任務個數  

    @Override  

    public 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;  

        /* 

         * 關鍵所在啊,如果任務隊列不空,則取出任務執行,若任務隊列空,則等待 

         */  

        @Override  

        public 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;  

}  

測試代碼:

//測試線程池  

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() });  

        System.out.println(t);  

        t.destroy();// 所有線程都執行完成才destory  

    // 任務類  

    static class Task implements Runnable {  

        private static volatile int i = 1;  

        public 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提供的線程池更加強大,相信了解線程池的工作原理,看類庫中的線程池就不會感到陌生了。

線程池的原理及實作(轉)
線程池的原理及實作(轉)

http://blog.csdn.net/hsuxu/article/details/8985931