ThreadPoolExecutor的原理及使用方法

来源:互联网 发布:手机用数据会出400bad 编辑:程序博客网 时间:2024/05/01 21:24

大家先从ThreadPoolExecutor的总体流程入手: 

针对ThreadPoolExecutor代码,我们来看下execute方法:

[java] view plain copy
 
 在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 plain copy
 
 在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 plain copy
 
 在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 plain copy
 
 在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 plain copy
 
 在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.     }  
  •     固定长度线程池
        好处:线程数量固定,不会存在线程重复初始化
        坏处:没有对队列大小进行限制,线程初始化后,再也不能回收线程资源
0 0
原创粉丝点击