Java 線程池的原理與實現

來源:互聯網
上載者:User

最近在學習線程池、記憶體控制等關於提高程式運行效能方面的編程技術,在網上看到有一哥們寫得不錯,故和大家一起分享。

[分享]Java 線程池的原理與實現

這幾天主要是狂看來源程式,在彌補了一些以前知識空白的同時,也學會了不少新的知識(比如 NIO),或者稱為新技術吧。
線程池就是其中之一,一提到線程,我們會想到以前《作業系統》的生產者與消費者,訊號量,同步控制等等。
一提到池,我們會想到資料庫連接池,但是線程池又如何呢?

建議:在閱讀本文前,先理一理同步的知識,特別是syncronized同步關鍵字的用法。
關於我對同步的認識,要緣於大三年的一本書,書名好像是 Java 實戰,這本書寫得實在太妙了,真正的從理論到實踐,從分析到.class位元組碼分析。哇,我想市場上很難買到這麼精緻的書了。作為一個Java愛好者,我覺得絕對值得一讀。
我對此書印象最深之一的就是:equal()方法,由淺入深,經典!
還有就是同步了,其中提到了我的幾個編程誤區,以前如何使用同步提高效能等等,通過學習,使我對同步的認識進一步加深。

簡單介紹

    建立線程有兩種方式:繼承Thread或實現Runnable。Thread實現了Runnable介面,提供了一個空的run()方法,所以不論是繼承Thread還是實現Runnable,都要有自己的run()方法。
    一個線程建立後就存在,調用start()方法就開始運行(執行run()方法),調用wait進入等待或調用sleep進入休眠期,順利運行完畢或休眠被中斷或運行過程中出現異常而退出。

wait和sleep比較:
      sleep方法有:sleep(long millis),sleep(long millis, long nanos),調用sleep方法後,當前線程進入休眠期,暫停執行,但該線程繼續擁有監視資源的所有權。到達休眠時間後線程將繼續執行,直到完成。若在休眠期另一線程中斷該線程,則該線程退出。
      wait方法有:wait(),wait(long timeout),wait(long timeout, long nanos),調用wait方法後,該線程放棄監視資源的所有權進入等待狀態;
      wait():等待有其它的線程調用notify()或notifyAll()進入調度狀態,與其它線程共同爭奪監視。wait()相當於wait(0),wait(0, 0)。
      wait(long timeout):當其它線程調用notify()或notifyAll(),或時間到達timeout亳秒,或有其它某線程中斷該線程,則該線程進入調度狀態。
      wait(long timeout, long nanos):相當於wait(1000000*timeout + nanos),只不過時間單位為納秒。

線程池:
    多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。
   
    假設一個伺服器完成一項任務所需時間為: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而在處理請求時浪費時間,從而提高效率。

/** 線程池類,背景工作執行緒作為其內部類 **/package org.ymcn.util;import java.util.Collections;import java.util.Date;import java.util.LinkedList;import java.util.List;import org.apache.log4j.Logger;/*** 線程池* 建立線程池,銷毀線程池,添加新任務** @author obullxl*/public final class ThreadPool {    private static Logger logger = Logger.getLogger(ThreadPool.class);    private static Logger taskLogger = Logger.getLogger("TaskLogger");    private static boolean debug = taskLogger.isDebugEnabled();    // private static boolean debug = taskLogger.isInfoEnabled();    /* 單例 */    private static ThreadPool instance = ThreadPool.getInstance();    public static final int SYSTEM_BUSY_TASK_COUNT = 150;    /* 預設池中線程數 */    public static int worker_num = 5;    /* 已經處理的任務數 */    private static int taskCounter = 0;    public static boolean systemIsBusy = false;    private static List<Task> taskQueue = Collections            .synchronizedList(new LinkedList<Task>());    /* 池中的所有線程 */    public PoolWorker[] workers;    private ThreadPool() {        workers = new PoolWorker[5];        for (int i = 0; i < workers.length; i++) {            workers[i] = new PoolWorker(i);        }    }    private ThreadPool(int pool_worker_num) {        worker_num = pool_worker_num;        workers = new PoolWorker[worker_num];        for (int i = 0; i < workers.length; i++) {            workers[i] = new PoolWorker(i);        }    }    public static synchronized ThreadPool getInstance() {        if (instance == null)            return new ThreadPool();        return instance;    }    /**    * 增加新的任務    * 每增加一個新任務,都要喚醒任務隊列    * @param newTask    */    public void addTask(Task newTask) {        synchronized (taskQueue) {            newTask.setTaskId(++taskCounter);            newTask.setSubmitTime(new Date());            taskQueue.add(newTask);            /* 喚醒隊列, 開始執行 */            taskQueue.notifyAll();        }        logger.info("Submit Task<" + newTask.getTaskId() + ">: "                + newTask.info());    }    /**    * 批量增加新任務    * @param taskes    */    public void batchAddTask(Task[] taskes) {        if (taskes == null || taskes.length == 0) {            return;        }        synchronized (taskQueue) {            for (int i = 0; i < taskes.length; i++) {                if (taskes[i] == null) {                    continue;                }                taskes[i].setTaskId(++taskCounter);                taskes[i].setSubmitTime(new Date());                taskQueue.add(taskes[i]);            }            /* 喚醒隊列, 開始執行 */            taskQueue.notifyAll();        }        for (int i = 0; i < taskes.length; i++) {            if (taskes[i] == null) {                continue;            }            logger.info("Submit Task<" + taskes[i].getTaskId() + ">: "                    + taskes[i].info());        }    }    /**    * 線程池資訊    * @return    */    public String getInfo() {        StringBuffer sb = new StringBuffer();        sb.append("\nTask Queue Size:" + taskQueue.size());        for (int i = 0; i < workers.length; i++) {            sb.append("\nWorker " + i + " is "                    + ((workers[i].isWaiting()) ? "Waiting." : "Running."));        }        return sb.toString();    }    /**    * 銷毀線程池    */    public synchronized void destroy() {        for (int i = 0; i < worker_num; i++) {            workers[i].stopWorker();            workers[i] = null;        }        taskQueue.clear();    }    /**    * 池中背景工作執行緒    *    * @author obullxl    */    private class PoolWorker extends Thread {        private int index = -1;        /* 該背景工作執行緒是否有效 */        private boolean isRunning = true;        /* 該背景工作執行緒是否可以執行新任務 */        private boolean isWaiting = true;        public PoolWorker(int index) {            this.index = index;            start();        }        public void stopWorker() {            this.isRunning = false;        }        public boolean isWaiting() {            return this.isWaiting;        }        /**        * 迴圈執行任務        * 這也許是線程池的關鍵所在        */        public void run() {            while (isRunning) {                Task r = null;                synchronized (taskQueue) {                    while (taskQueue.isEmpty()) {                        try {                            /* 任務隊列為空白,則等待有新任務加入從而被喚醒 */                            taskQueue.wait(20);                        } catch (InterruptedException ie) {                            logger.error(ie);                        }                    }                    /* 取出任務執行 */                    r = (Task) taskQueue.remove(0);                }                if (r != null) {                    isWaiting = false;                    try {                        if (debug) {                            r.setBeginExceuteTime(new Date());                            taskLogger.debug("Worker<" + index                                    + "> start execute Task<" + r.getTaskId() + ">");                            if (r.getBeginExceuteTime().getTime()                                    - r.getSubmitTime().getTime() > 1000)                                taskLogger.debug("longer waiting time. "                                        + r.info() + ",<" + index + ">,time:"                                        + (r.getFinishTime().getTime() - r                                                .getBeginExceuteTime().getTime()));                        }                        /* 該任務是否需要立即執行 */                        if (r.needExecuteImmediate()) {                            new Thread(r).start();                        } else {                            r.run();                        }                        if (debug) {                            r.setFinishTime(new Date());                            taskLogger.debug("Worker<" + index                                    + "> finish task<" + r.getTaskId() + ">");                            if (r.getFinishTime().getTime()                                    - r.getBeginExceuteTime().getTime() > 1000)                                taskLogger.debug("longer execution time. "                                        + r.info() + ",<" + index + ">,time:"                                        + (r.getFinishTime().getTime() - r                                                .getBeginExceuteTime().getTime()));                        }                    } catch (Exception e) {                        e.printStackTrace();                        logger.error(e);                    }                    isWaiting = true;                    r = null;                }            }        }    }}

 

/** 任務介面類 **/package org.ymcn.util;import java.util.Date;/*** 所有任務介面* 其他任務必須繼承訪類** @author obullxl*/public abstract class Task implements Runnable {    // private static Logger logger = Logger.getLogger(Task.class);    /* 產生時間 */    private Date generateTime = null;    /* 提交執行時間 */    private Date submitTime = null;    /* 開始執行時間 */    private Date beginExceuteTime = null;    /* 執行完成時間 */    private Date finishTime = null;    private long taskId;    public Task() {        this.generateTime = new Date();    }    /**    * 任務執行入口    */    public void run() {        /**        * 相關執行代碼        *        * beginTransaction();        *        * 執行過程中可能產生新的任務 subtask = taskCore();        *        * commitTransaction();        *        * 增加新產生的任務 ThreadPool.getInstance().batchAddTask(taskCore());        */    }    /**    * 所有任務的核心 所以特別的商務邏輯執行之處    *    * @throws Exception    */    public abstract Task[] taskCore() throws Exception;    /**    * 是否用到資料庫    *    * @return    */    protected abstract boolean useDb();    /**    * 是否需要立即執行    *    * @return    */    protected abstract boolean needExecuteImmediate();    /**    * 任務資訊    *    * @return String    */    public abstract String info();    public Date getGenerateTime() {        return generateTime;    }    public Date getBeginExceuteTime() {        return beginExceuteTime;    }    public void setBeginExceuteTime(Date beginExceuteTime) {        this.beginExceuteTime = beginExceuteTime;    }    public Date getFinishTime() {        return finishTime;    }    public void setFinishTime(Date finishTime) {        this.finishTime = finishTime;    }    public Date getSubmitTime() {        return submitTime;    }    public void setSubmitTime(Date submitTime) {        this.submitTime = submitTime;    }    public long getTaskId() {        return taskId;    }    public void setTaskId(long taskId) {        this.taskId = taskId;    }}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.