<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    最近在學(xué)習(xí)線程池、內(nèi)存控制等關(guān)于提高程序運行性能方面的編程技術(shù),在網(wǎng)上看到有一哥們寫得不錯,故和大家一起分享。

    [分享]Java 線程池的原理與實現(xiàn)


    這幾天主要是狂看源程序,在彌補了一些以前知識空白的同時,也學(xué)會了不少新的知識(比如 NIO),或者稱為新技術(shù)吧。
    線程池就是其中之一,一提到線程,我們會想到以前《操作系統(tǒng)》的生產(chǎn)者與消費者,信號量,同步控制等等。
    一提到池,我們會想到數(shù)據(jù)庫連接池,但是線程池又如何呢?


    建議:在閱讀本文前,先理一理同步的知識,特別是syncronized同步關(guān)鍵字的用法。
    關(guān)于我對同步的認(rèn)識,要緣于大三年的一本書,書名好像是 Java 實戰(zhàn),這本書寫得實在太妙了,真正的從理論到實踐,從截圖分析到.class字節(jié)碼分析。哇,我想市場上很難買到這么精致的書了。作為一個Java愛好者,我覺得絕對值得一讀。
    我對此書印象最深之一的就是:equal()方法,由淺入深,經(jīng)典!
    還有就是同步了,其中提到了我的幾個編程誤區(qū),以前如何使用同步提高性能等等,通過學(xué)習(xí),使我對同步的認(rèn)識進一步加深。


    簡單介紹

        創(chuàng)建線程有兩種方式:繼承Thread或?qū)崿F(xiàn)Runnable。Thread實現(xiàn)了Runnable接口,提供了一個空的run()方法,所以不論是繼承Thread還是實現(xiàn)Runnable,都要有自己的run()方法。
        一個線程創(chuàng)建后就存在,調(diào)用start()方法就開始運行(執(zhí)行run()方法),調(diào)用wait進入等待或調(diào)用sleep進入休眠期,順利運行完畢或休眠被中斷或運行過程中出現(xiàn)異常而退出。

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



    線程池:
        多線程技術(shù)主要解決處理器單元內(nèi)多個線程執(zhí)行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。
       
        假設(shè)一個服務(wù)器完成一項任務(wù)所需時間為:T1 創(chuàng)建線程時間,T2 在線程中執(zhí)行任務(wù)的時間,T3 銷毀線程時間。
       
        如果:T1 + T3 遠大于 T2,則可以采用線程池,以提高服務(wù)器性能。
                    一個線程池包括以下四個基本組成部分:
                    1、線程池管理器(ThreadPool):用于創(chuàng)建并管理線程池,包括 創(chuàng)建線程池,銷毀線程池,添加新任務(wù);
                    2、工作線程(PoolWorker):線程池中線程,在沒有任務(wù)時處于等待狀態(tài),可以循環(huán)的執(zhí)行任務(wù);
                    3、任務(wù)接口(Task):每個任務(wù)必須實現(xiàn)的接口,以供工作線程調(diào)度任務(wù)的執(zhí)行,它主要規(guī)定了任務(wù)的入口,任務(wù)執(zhí)行完后的收尾工作,任務(wù)的執(zhí)行狀態(tài)等;
                    4、任務(wù)隊列(taskQueue):用于存放沒有處理的任務(wù)。提供一種緩沖機制。
                   
        線程池技術(shù)正是關(guān)注如何縮短或調(diào)整T1,T3時間的技術(shù),從而提高服務(wù)器程序性能的。它把T1,T3分別安排在服務(wù)器程序的啟動和結(jié)束的時間段或者一些空閑的時間段,這樣在服務(wù)器程序處理客戶請求時,不會有T1,T3的開銷了。

        線程池不僅調(diào)整T1,T3產(chǎn)生的時間段,而且它還顯著減少了創(chuàng)建線程的數(shù)目,看一個例子:

        假設(shè)一個服務(wù)器一天要處理50000個請求,并且每個請求需要一個單獨的線程完成。在線程池中,線程數(shù)一般是固定的,所以產(chǎn)生線程總數(shù)不會超過線程池中線程的數(shù)目,而如果服務(wù)器不利用線程池來處理這些請求則線程總數(shù)為50000。一般線程池大小是遠小于50000。所以利用線程池的服務(wù)器程序不會為了創(chuàng)建50000而在處理請求時浪費時間,從而提高效率。


    /** 線程池類,工作線程作為其內(nèi)部類 **/

    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;

    /**
    * 線程池
    * 創(chuàng)建線程池,銷毀線程池,添加新任務(wù)
    *
    * @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;
        /* 默認(rèn)池中線程數(shù) */
        public static int worker_num = 5;
        /* 已經(jīng)處理的任務(wù)數(shù) */
        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;
        }
        /**
        * 增加新的任務(wù)
        * 每增加一個新任務(wù),都要喚醒任務(wù)隊列
        * @param newTask
        */
        public void addTask(Task newTask) {
            synchronized (taskQueue) {
                newTask.setTaskId(++taskCounter);
                newTask.setSubmitTime(new Date());
                taskQueue.add(newTask);
                /* 喚醒隊列, 開始執(zhí)行 */
                taskQueue.notifyAll();
            }
            logger.info("Submit Task<" + newTask.getTaskId() + ">: "
                    + newTask.info());
        }
        /**
        * 批量增加新任務(wù)
        * @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]);
                }
                /* 喚醒隊列, 開始執(zhí)行 */
                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;
            /* 該工作線程是否可以執(zhí)行新任務(wù) */
            private boolean isWaiting = true;

            public PoolWorker(int index) {
                this.index = index;
                start();
            }

            public void stopWorker() {
                this.isRunning = false;
            }

            public boolean isWaiting() {
                return this.isWaiting;
            }
            /**
            * 循環(huán)執(zhí)行任務(wù)
            * 這也許是線程池的關(guān)鍵所在
            */
            public void run() {
                while (isRunning) {
                    Task r = null;
                    synchronized (taskQueue) {
                        while (taskQueue.isEmpty()) {
                            try {
                                /* 任務(wù)隊列為空,則等待有新任務(wù)加入從而被喚醒 */
                                taskQueue.wait(20);
                            } catch (InterruptedException ie) {
                                logger.error(ie);
                            }
                        }
                        /* 取出任務(wù)執(zhí)行 */
                        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()));
                            }
                            /* 該任務(wù)是否需要立即執(zhí)行 */
                            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;
                    }
                }
            }
        }
    }

    /** 任務(wù)接口類 **/

    package org.ymcn.util;

    import java.util.Date;

    /**
    * 所有任務(wù)接口
    * 其他任務(wù)必須繼承訪類
    *
    * @author obullxl
    */
    public abstract class Task implements Runnable {
        // private static Logger logger = Logger.getLogger(Task.class);
        /* 產(chǎn)生時間 */
        private Date generateTime = null;
        /* 提交執(zhí)行時間 */
        private Date submitTime = null;
        /* 開始執(zhí)行時間 */
        private Date beginExceuteTime = null;
        /* 執(zhí)行完成時間 */
        private Date finishTime = null;

        private long taskId;

        public Task() {
            this.generateTime = new Date();
        }

        /**
        * 任務(wù)執(zhí)行入口
        */
        public void run() {
            /**
            * 相關(guān)執(zhí)行代碼
            *
            * beginTransaction();
            *
            * 執(zhí)行過程中可能產(chǎn)生新的任務(wù) subtask = taskCore();
            *
            * commitTransaction();
            *
            * 增加新產(chǎn)生的任務(wù) ThreadPool.getInstance().batchAddTask(taskCore());
            */
        }

        /**
        * 所有任務(wù)的核心 所以特別的業(yè)務(wù)邏輯執(zhí)行之處
        *
        * @throws Exception
        */
        public abstract Task[] taskCore() throws Exception;

        /**
        * 是否用到數(shù)據(jù)庫
        *
        * @return
        */
        protected abstract boolean useDb();

        /**
        * 是否需要立即執(zhí)行
        *
        * @return
        */
        protected abstract boolean needExecuteImmediate();

        /**
        * 任務(wù)信息
        *
        * @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;
        }

    }



    轉(zhuǎn)自:http://hi.baidu.com/obullxl/blog/item/ee50ad1ba8e8ff1f8718bf66.html
    posted on 2008-10-17 23:20 李威威 閱讀(105991) 評論(12)  編輯  收藏
    Comments
    • # re: Java 線程池的原理與實現(xiàn)
      強尼戴普
      Posted @ 2012-06-18 17:03
      代碼可以加于適當(dāng)注釋么?  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      gqh
      Posted @ 2012-06-29 19:43
      你說的是哪本書??  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)[未登錄]
      azhqiang
      Posted @ 2012-09-05 18:13
      學(xué)習(xí)下,就是注釋好少。  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      謝劍英
      Posted @ 2013-03-11 19:38
      寫的不錯,我也一直納悶,線程池是怎么保持線程的,現(xiàn)在重要明白了。
        回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      張永紅
      Posted @ 2013-08-27 11:10
      例子中有一點不太明白,有個參數(shù)叫做 是否立即執(zhí)行?
      為什么為真時,是創(chuàng)建另外的線程執(zhí)行。
      為假時,是直接調(diào)用run方法。
      這個我感覺跟立即執(zhí)行沒什么關(guān)系,反而參數(shù)的意思是,是否需要額外的線程執(zhí)行。  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      alviss
      Posted @ 2013-08-30 11:51
      立即執(zhí)行應(yīng)該是在提交任務(wù)的時候,首先是查看線程池中是否有空閑的工作線程,如果有就執(zhí)行,如果沒有就開啟另外的線程執(zhí)行。我的理解是這樣。  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      testqwer
      Posted @ 2014-02-18 14:25
      你好,你說的那本書能想起全名嗎  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      can
      Posted @ 2014-03-31 11:38
      @testqwer
      應(yīng)該是Java開發(fā)實戰(zhàn)經(jīng)典,李興華著  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      didafor
      Posted @ 2014-11-18 12:52
      可以去struts教程網(wǎng)上看看,有一篇文章是講解構(gòu)建一個簡單的線程池的感覺不錯。  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      didafor
      Posted @ 2014-11-18 12:53
      可以看看這篇文章,構(gòu)建一個簡單的線程池:http://www.strutshome.com/index.php/archives/710  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      xxxxx
      Posted @ 2015-09-08 22:09
      禍害不少人  回復(fù)  更多評論   
    • # re: Java 線程池的原理與實現(xiàn)
      re: Java 線程池的原理與實現(xiàn)
      Posted @ 2015-12-07 10:13
      re: Java 線程池的原理與實現(xiàn)  回復(fù)  更多評論   

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
     
    主站蜘蛛池模板: 日韩视频免费在线| 久久综合亚洲色HEZYO社区| 人妻在线日韩免费视频| 亚洲男人电影天堂| 免费人成在线观看播放国产| 香蕉免费在线视频| 亚洲综合色区中文字幕| 久久国产成人亚洲精品影院| 在线日本高清免费不卡| 精品久久久久久久久亚洲偷窥女厕| 中文字幕人成人乱码亚洲电影| 国产免费丝袜调教视频| 特级无码毛片免费视频| 久久亚洲国产精品成人AV秋霞| 国产女高清在线看免费观看| 91禁漫免费进入| 欧亚一级毛片免费看| 亚洲成AV人综合在线观看| 亚洲国产一成久久精品国产成人综合 | 精品久久久久久无码免费| 亚洲人成高清在线播放| 亚洲欧洲一区二区三区| 最近最新MV在线观看免费高清| 中文字幕无线码免费人妻| 亚洲人成网站色7799| 亚洲色欲或者高潮影院| 国产亚洲精品线观看动态图| 女人被男人桶得好爽免费视频| 无码国产精品一区二区免费模式| 野花视频在线官网免费1| 精品亚洲国产成人| 亚洲av无码专区国产乱码在线观看 | 欧亚精品一区三区免费| 未满十八18禁止免费无码网站| 国产成人亚洲综合无| 亚洲国产精品一区二区三区在线观看 | yy6080久久亚洲精品| 欧亚精品一区三区免费| 在线免费观看你懂的| 久久99热精品免费观看牛牛| 国产精品青草视频免费播放|