1. 程式人生 > >Java執行緒池實現原理與技術I

Java執行緒池實現原理與技術I

無限制執行緒的缺陷

多執行緒的軟體設計方法確實可以最大限度地發揮多核處理器的計算能力,提高生產系統的吞吐量和效能。但是,若不加控制和管理的隨意使用執行緒,對系統的效能反而會產生不利的影響。

一種最為簡單的執行緒建立和回收的方法類似如下:

new Thread(new Runnable() {
    @Override
    public void run() {
        //do sth
    }
}).start();

以上程式碼建立了一條執行緒,並在run()方法結束後,自動回收該執行緒。在簡單的應用系統中,這段程式碼並沒有太多問題。但是在真實的生產環境中,系統由於真實環境的需要,可能會開啟很多執行緒來支撐其應用。而當執行緒數量過大時,反而會耗盡CPU和記憶體資源。

首先,雖然與程序相比,執行緒是一種輕量級的工具,但其建立和關閉依然需要花費時間,如果為每一個小的任務都建立一個執行緒,很有可能出現建立和銷燬執行緒所佔用的時間大於該執行緒真實工作所消耗的時間,反而會得不償失。

其次,執行緒本身也是要佔用記憶體空間的,大量的執行緒會搶佔寶貴的內部資源。

因此,在實際生產環境中,執行緒的數量必須得到控制。盲目地大量建立執行緒對系統性能是有傷害的。

簡單的執行緒池實現

下面給出一個最簡單的執行緒池,該執行緒池不是一個完善的執行緒池,但已經實現了一個基本執行緒池的核心功能,有助於快速理解執行緒池的實現。

1、執行緒池的實現

public class ThreadPool {
    private static ThreadPool instance = null;

    //空閒的執行緒佇列
    private List<PThread> idleThreads;
    //已有的執行緒總數
    private int threadCounter;
    private boolean isShutDown = false;

    private ThreadPool() {
        this.idleThreads = new Vector<>(5);
        threadCounter = 0;
    }

    public int getCreatedThreadCounter() {
        return threadCounter;
    }

    //取得執行緒池的例項
    public synchronized static ThreadPool getInstance() {
        if (instance == null) {
            instance = new ThreadPool();
        }
        return instance;
    }

    //將執行緒池放入池中
    protected synchronized void repool(PThread repoolingThread) {
        if (!isShutDown) {
            idleThreads.add(repoolingThread);
        } else {
            repoolingThread.shutDown();
        }
    }

    //停止池中所有執行緒
    public synchronized void shutDown() {
        isShutDown = true;
        for (int threadIndex = 0; threadIndex < idleThreads.size(); threadIndex++) {
            PThread pThread = idleThreads.get(threadIndex);
            pThread.shutDown();
        }
    }

    //執行任務
    public synchronized void start(Runnable target) {
        PThread thread = null;
        //如果有空閒執行緒,則直接使用
        if (idleThreads.size() > 0) {
            int lastIndex = idleThreads.size() - 1;
            thread = idleThreads.get(lastIndex);
            idleThreads.remove(thread);
            //立即執行這個任務
            thread.setTarget(target);
        }//沒有空閒執行緒,則建立執行緒
        else {
            threadCounter++;
            //建立新執行緒
            thread = new PThread(target, "PThread #" + threadCounter, this);
            //啟動這個執行緒
            thread.start();
        }
    }

}

2、要實現上面的執行緒池,就需要一個永不退出的執行緒與之配合。PThread就是一個這樣的執行緒。它的主體部分是一個無限迴圈,該執行緒在手動關閉前永不結束,並一直等待新的任務到達。

public class PThread extends Thread {
    //執行緒池
    private ThreadPool pool;
    //任務
    private Runnable target;
    private boolean isShutDown = false;
    private boolean isIdle = false; //是否閒置
    //建構函式
    public PThread(Runnable target,String name, ThreadPool pool){
        super(name);
        this.pool = pool;
        this.target = target;
    }

    public Runnable getTarget(){
        return target;
    }

    public boolean isIdle() {
        return isIdle;
    }

    @Override
    public void run() {
        //只要沒有關閉,則一直不結束該執行緒
        while (!isShutDown){
            isIdle =  false;
            if (target != null){
                //執行任務
                target.run();
            }
            try {
                //任務結束了,到閒置狀態
                isIdle = true;
                pool.repool(this);
                synchronized (this){
                    //執行緒空閒,等待新的任務到來
                    wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            isIdle = false;
        }
    }

    public synchronized void setTarget(Runnable newTarget){
        target = newTarget;
        //設定了任務之後,通知run方法,開始執行這個任務
        notifyAll();
    }

    //關閉執行緒
    public synchronized void shutDown(){
        isShutDown = true;
        notifyAll();
    }

}

3、測試Main方法

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 1000; i++) {
            ThreadPool.getInstance().start(new Runnable() {
                @Override
                public void run() {
                    try {
                        //休眠100ms
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

執行緒池如此常用,以致於jdk自帶了一些執行緒池框架,例如 ThreadPoolExecutor,以及基於ThreadPoolExecutor實現的Executor框架 。關於執行緒池框架的介紹,限於篇幅,等待下回分解。

 

關注後端技術精選,每天推送優質好文

Java執行緒池實現原理與技術I