線程池ThreadPoolExecutor


http://blog.csdn.net/xiamizy/article/details/40781939

大家先從ThreadPoolExecutor的總體流程入手: 

針對ThreadPoolExecutor代碼,我們來看下execute方法:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public void execute(Runnable command) {  
  2.         if (command == null)  
  3.             throw new NullPointerException();  
  4.     //poolSize大於等於corePoolSize時不增加線程,反之新初始化線程  
  5.         if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {  
  6.         //線程執行狀態外爲執行,同時可以添加到隊列中  
  7.             if (runState == RUNNING && workQueue.offer(command)) {  
  8.                 if (runState != RUNNING || poolSize == 0)  
  9.                     ensureQueuedTaskHandled(command);  
  10.             }  
  11.         //poolSize大於等於corePoolSize時,新初始化線程  
  12.             else if (!addIfUnderMaximumPoolSize(command))  
  13.         //無法添加初始化執行線程,怎麼執行reject操作(調用RejectedExecutionHandler)  
  14.                 reject(command); // is shutdown or saturated  
  15.         }  
  16.     }  

 我們再看下真正的線程執行者(Worker):

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. private final class Worker implements Runnable {  
  2. /** 
  3.         * Runs a single task between before/after methods. 
  4.         */  
  5.        private void runTask(Runnable task) {  
  6.            final ReentrantLock runLock = this.runLock;  
  7.            runLock.lock();  
  8.            try {  
  9.                /* 
  10.                 * If pool is stopping ensure thread is interrupted; 
  11.                 * if not, ensure thread is not interrupted. This requires 
  12.                 * a double-check of state in case the interrupt was 
  13.                 * cleared concurrently with a shutdownNow -- if so, 
  14.                 * the interrupt is re-enabled. 
  15.                 */  
  16.      //當線程池的執行狀態爲關閉等,則執行當前線程的interrupt()操作  
  17.                if ((runState >= STOP ||  
  18.                    (Thread.interrupted() && runState >= STOP)) &&  
  19.                    hasRun)  
  20.                    thread.interrupt();  
  21.                /* 
  22.                 * Track execution state to ensure that afterExecute 
  23.                 * is called only if task completed or threw 
  24.                 * exception. Otherwise, the caught runtime exception 
  25.                 * will have been thrown by afterExecute itself, in 
  26.                 * which case we don't want to call it again. 
  27.                 */  
  28.                boolean ran = false;  
  29.                beforeExecute(thread, task);  
  30.                try {  
  31.         //任務執行  
  32.                    task.run();  
  33.                    ran = true;  
  34.                    afterExecute(task, null);  
  35.                    ++completedTasks;  
  36.                } catch (RuntimeException ex) {  
  37.                    if (!ran)  
  38.                        afterExecute(task, ex);  
  39.                    throw ex;  
  40.                }  
  41.            } finally {  
  42.                runLock.unlock();  
  43.            }  
  44.        }  
  45.   
  46.        /** 
  47.         * Main run loop 
  48.         */  
  49.        public void run() {  
  50.            try {  
  51.                hasRun = true;  
  52.                Runnable task = firstTask;  
  53.                firstTask = null;  
  54.     //判斷是否存在需要執行的任務  
  55.                while (task != null || (task = getTask()) != null) {  
  56.                    runTask(task);  
  57.                    task = null;  
  58.                }  
  59.            } finally {  
  60.     //如果沒有,則將工作線程移除,當poolSize爲0是則嘗試關閉線程池  
  61.                workerDone(this);  
  62.            }  
  63.        }  
  64.    }  
  65.   
  66.    /* Utilities for worker thread control */  
  67.   
  68.    /** 
  69.     * Gets the next task for a worker thread to run.  The general 
  70.     * approach is similar to execute() in that worker threads trying 
  71.     * to get a task to run do so on the basis of prevailing state 
  72.     * accessed outside of locks.  This may cause them to choose the 
  73.     * "wrong" action, such as trying to exit because no tasks 
  74.     * appear to be available, or entering a take when the pool is in 
  75.     * the process of being shut down.  These potential problems are 
  76.     * countered by (1) rechecking pool state (in workerCanExit) 
  77.     * before giving up, and (2) interrupting other workers upon 
  78.     * shutdown, so they can recheck state. All other user-based state 
  79.     * changes (to allowCoreThreadTimeOut etc) are OK even when 
  80.     * performed asynchronously wrt getTask. 
  81.     * 
  82.     * @return the task 
  83.     */  
  84.    Runnable getTask() {  
  85.        for (;;) {  
  86.            try {  
  87.                int state = runState;  
  88.                if (state > SHUTDOWN)  
  89.                    return null;  
  90.                Runnable r;  
  91.                if (state == SHUTDOWN)  // Help drain queue  
  92.                    r = workQueue.poll();  
  93.     //當線程池大於corePoolSize,同時,存在執行超時時間,則等待相應時間,拿出隊列中的線程  
  94.                else if (poolSize > corePoolSize || allowCoreThreadTimeOut)  
  95.                    r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);  
  96.                else  
  97.     //阻塞等待隊列中可以取到新線程  
  98.                    r = workQueue.take();  
  99.                if (r != null)  
  100.                    return r;  
  101.     //判斷線程池運行狀態,如果大於corePoolSize,或者線程隊列爲空,也或者線程池爲終止的工作線程可以銷燬  
  102.                if (workerCanExit()) {  
  103.                    if (runState >= SHUTDOWN) // Wake up others  
  104.                        interruptIdleWorkers();  
  105.                    return null;  
  106.                }  
  107.                // Else retry  
  108.            } catch (InterruptedException ie) {  
  109.                // On interruption, re-check runState  
  110.            }  
  111.        }  
  112.    }  
  113.   
  114.     /** 
  115.     * Performs bookkeeping for an exiting worker thread. 
  116.     * @param w the worker 
  117.     */  
  118.     //記錄執行任務數量,將工作線程移除,當poolSize爲0是則嘗試關閉線程池  
  119.    void workerDone(Worker w) {  
  120.        final ReentrantLock mainLock = this.mainLock;  
  121.        mainLock.lock();  
  122.        try {  
  123.            completedTaskCount += w.completedTasks;  
  124.            workers.remove(w);  
  125.            if (--poolSize == 0)  
  126.                tryTerminate();  
  127.        } finally {  
  128.            mainLock.unlock();  
  129.        }  
  130.    }  

 

 通過上述代碼,總結下四個關鍵字的用法

  • corePoolSize 核心線程數量

線程保有量,線程池總永久保存執行線程的數量

  • maximumPoolSize 最大線程數量

最大線程量,線程最多不能超過此屬性設置的數量,當大於線程保有量後,會新啓動線程來滿足線程執行。

  • 線程存活時間

獲取隊列中任務的超時時間,當閾值時間內無法獲取線程,則會銷燬處理線程,前提是線程數量在corePoolSize 以上

  • 執行隊列

執行隊列是針對任務的緩存,任務在提交至線程池時,都會壓入到執行隊列中。所以這裏大家最好設置下隊列的上限,防止溢出

 

ThreadPoolExecuter的幾種實現

 

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public static ExecutorService newCachedThreadPool() {  
  2.       return new ThreadPoolExecutor(0, Integer.MAX_VALUE,  
  3.                                     60L, TimeUnit.SECONDS,  
  4.                                     new SynchronousQueue<Runnable>());  
  5.   }  
  •  CachedThreadPool 執行線程不固定,
     好處:可以把新增任務全部緩存在一起,
     壞處:只能用在短時間完成的任務(佔用時間較長的操作可以導致線程數無限增大,系統資源耗盡)
[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public static ExecutorService newSingleThreadExecutor() {  
  2.         return new FinalizableDelegatedExecutorService  
  3.             (new ThreadPoolExecutor(11,  
  4.                                     0L, TimeUnit.MILLISECONDS,  
  5.                                     new LinkedBlockingQueue<Runnable>()));  
  6.     }  
  •  單線程線程池
       好處:針對單cpu,單線程避免系統資源的搶奪
       壞處:多cpu多線程時,不能完全利用cpu資源
[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public static ExecutorService newFixedThreadPool(int nThreads) {  
  2.         return new ThreadPoolExecutor(nThreads, nThreads,  
  3.                                       0L, TimeUnit.MILLISECONDS,  
  4.                                       new LinkedBlockingQueue<Runnable>(),  
  5.                                       threadFactory);  
  6.     }  
  •     固定長度線程池
        好處:線程數量固定,不會存在線程重複初始化
        壞處:沒有對隊列大小進行限制,線程初始化後,再也不能回收線程資源

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章