Java線程池的原理及實現

jopen 9年前發布 | 12K 次閱讀 Java線程 Java開發

  多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。    
    假設一個服務器完成一項任務所需時間為: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 dhp.util.thread;

import java.util.LinkedList;  
import java.util.List;  

/** 
 * 線程池類,線程管理器:創建線程,執行任務,銷毀線程,獲取線程基本信息 
 * @author 鄧海波 
 * 
 */  
public final class ThreadPool {  
    // 線程池中默認線程的個數為5    
    private static int worker_num = 5;  
    // 工作線程  
    private WorkThread[] workThreads;  
    // 處理的任務  
    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;    
        workThreads = new WorkThread[worker_num];    
        for (int i = 0; i < worker_num; i++) {    
            workThreads[i] = new WorkThread();    
            workThreads[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();    
            }    
        }    
        // 工作線程停止工作,且置為null    
        for (int i = 0; i < worker_num; i++) {    
            workThreads[i].stopWorker();    
            workThreads[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();    
    }    
    /** 
     * 內部類,工作線程 
     * @author 鄧海波 
     * 
     */  
    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;    
        }    
    }  
}  </pre><br />

    package dhp.util.thread;
/**

 * 測試線程池 
 * @author 鄧海波 
 * 
 */  
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();// 所有線程都執行完成才destory    
        System.out.println(t);    
    }    

    // 任務類    
    static class Task implements Runnable {    
        private static volatile int i = 1;    

        @Override    
        public void run() {// 執行任務    
            System.out.println("任務 " + (i++) + " 完成");    
        }    
    }    
}  </pre><br />
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!