码迷,mamicode.com
首页 > 其他好文 > 详细

J.U.C ThreadPoolExecutor解析

时间:2015-06-26 21:08:10      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:

     Java里面线程池顶级接口是Executor,但严格意义上讲Executor并不是一个线程池,而是一个线程执行工具,真正的线程池接口是ExecutorService.关系类图如下:

技术分享

        首先Executor的execute方法只是执行一个Runnable任务而已,当然从某种角度上讲最后的实现类也是在线程中启动该任务。

void execute(Runnable command);

        ExecutorService在Executor的基础上增加了一些任务提交方法:

  <T> Future<T> submit(Callable<T> task);
  <T> Future<T> submit(Runnable task, T result);  
  Future<?> submit(Runnable task);

      这些方法都是向线程池提交任务,与Executor.execute()不同的是:Executor方法中在执行完毕后没有结果,而ExecutorService.submit()方法在任务执行完毕后会返回一个结果。这在多个线程中传递状态和结果是非常哟用。这三种方法都返回一个Future对象,Future对象可以阻塞线程知道任务执行完毕(获得结果,如果有的话),也可以取消任务执行,当然也能检测任务是否是被取消或者是否执行完毕。

      在没有Future之前我们检测一个线程是否执行完毕通常使用Thread.join()或者用一个死循环加状态来描述线程任务执行完毕。现在有了更哈的方法来阻塞线程,检测任务执行完毕甚至取消执行中的或者未开始执行的任务。

      另外ExecutorService加入一些作为一种服务而具有的服务方法,这也是为什么上面说executor Service才是作为线程池接口的真正原因:

    List<Runnable> shutdownNow();
    void shutdown();
    boolean isShutdown();
    boolean isTerminated();
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

       其中shutdown,shutdownNow的区别在于,shutdown对应线程池实现类ThreadPoolExecutor内部的SHUTDOWN状态,该状态下,线程池会拒绝接受新任务,并继续运行真在运行和尚未运行在blocking queue队列中的任务,最后停止;而shutdownNow对应线程池内部的STOP状态,该状态下,线程池拒绝新任务的提交,并尝试停止真在运行的任务(前提该任务可interrupt),并取消队列中等待执行的任务,并返回一个为执行任务list.

 

一:ThreadPoolExecutor构造器

 

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {

     下面解释下一下构造器中各个参数的含义:

  • corePoolSize:   核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,(线程数小于corePoolSize时,就算有idle线程,也是新建一个thread处理新任务)而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
  • maximumPoolSize:   线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
  • keepAliveTime:   表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
  • unit:   参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS;               //
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒
  • workQueue:  一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
  • threadFactory: 线程工厂,主要用来创建线程;
  • handler: 表示当拒绝处理任务时的策略,有以下四种取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 

 

二:线程池实现原理源码解析(1.7)

    1.线程池状态和线程数分析:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;

private static final int RUNNING = -1 << COUNT_BITS;

private static final int SHUTDOWN = 0 << COUNT_BITS;

private static final int STOP = 1 << COUNT_BITS;

private static final int TIDYING = 2 << COUNT_BITS;

private static final int TERMINATED = 3 << COUNT_BITS;

     AtomicInterger类型的ctl状态变量,用一个integer(32)来包含线程池状态和数量的表示,高三位为线程池状态位,后(2^29)-1 (大约 500 百万)为线程数限制,目前够用,作者Doug lea表示未来扩展可通过long类型来突破线程数大小限制 (atomic类型保证内存可见性的同时,支持CAS无锁原子性操作,在源码中到处充斥了该操作,提高并发性); 

   下面的几个static final变量表示runState可能的几个取值。

    当创建线程池后,初始时,线程池处于RUNNING状态;

    如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;

    如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;

        TIDYING:当线程池所有tasks都terminated,并且线程数为0的状态,该状态下会调用terminated()方法,向terminated状态转变。

    当terminated()方法执行完毕后,线程池被设置为TERMINATED状态。

        下面是简单的状态转变情况:

     *  RUNNING -> SHUTDOWN
     *    On invocation of shutdown(), perhaps implicitly in finalize()
     * (RUNNING or SHUTDOWN) -> STOP
     *    On invocation of shutdownNow()
     * SHUTDOWN -> TIDYING
     *    When both queue and pool are empty
     * STOP -> TIDYING
     *    When pool is empty
     * TIDYING -> TERMINATED
     *    When the terminated() hook method has completed
    

        下面是ctl变量与状态,线程数之间包装和解包装(一些mask,offset bit操作):

    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }

         状态判断方法:

    //通过int比较,刚表述了该int由两部分组成 runState | number ,线程池运行过程中
//线程数number的变化,并不影响高位状态runState作为int的比较.
private static boolean runStateLessThan(int c, int s) { return c < s; } private static boolean runStateAtLeast(int c, int s) { return c >= s; } private static boolean isRunning(int c) { return c < SHUTDOWN; }

 

     2:任务的执行:

     在了解将任务提交给线程池到任务执行完毕整个过程之前,我们先来看一下ThreadPoolExecutor类中其他的一些比较重要成员变量:

    private final BlockingQueue<Runnable> workQueue;//线程池任务队列,用于存放等待执行的任务

    private final ReentrantLock mainLock = new ReentrantLock();//用于线程池一些统计信息更新时的锁,e.g.如下的largestPoolSize,complectedTaskNum,ctl的状态和线程数更新时。

    private final HashSet<Worker> workers = new HashSet<Worker>();//线程池工作集,Runnable的实现,里面封装了thread变量成员,用于执行任务

    private final Condition termination = mainLock.newCondition();//客户端调用awaitTerminate()时,将阻塞与此,线程池处于terminate后,会调用condition.signalAll()通知(有time参数的另外考虑)。

    private int largestPoolSize;//用于记录线程池运行过程曾出现过得最大线程数,不同于maxiumPoolSize

    private long completedTaskCount; //用于动态记录线程池完成的任务数

    private volatile ThreadFactory threadFactory;//用于创建新的线程,newThread(Runnable).

    private volatile RejectedExecutionHandler handler;//拒绝任务提交的处理器

    private volatile long keepAliveTime;//当线程数大于corePoolsize时,多出那部分线程处于idle状态时,最大保活时间。

    private volatile boolean allowCoreThreadTimeOut;//当线程数小于corePoolsize时,是否允许其也运用保活时间限制。

    private volatile int corePoolSize; //核心池的大小(即线程池中的线程数目大于这个参数时,提交的任务会被放进任务缓存队列)

    private volatile int maximumPoolSize;//线程池运行的最大线程数。

   每个变量的作用都已经标明出来了,这里要重点解释一下corePoolSize、maximumPoolSize、largestPoolSize三个变量。

  corePoolSize在很多地方被翻译成核心池大小,其实我的理解这个就是线程池的大小。举个简单的例子:

  假如有一个工厂,工厂里面有10个工人,每个工人同时只能做一件任务。

  因此只要当10个工人中有工人是空闲的,来了任务就分配给空闲的工人做;

  当10个工人都有任务在做时,如果还来了任务,就把任务进行排队等待;

  如果说新任务数目增长的速度远远大于工人做任务的速度,那么此时工厂主管可能会想补救措施,比如重新招4个临时工人进来;

  然后就将任务也分配给这4个临时工人做;

  如果说着14个工人做任务的速度还是不够,此时工厂主管可能就要考虑不再接收新的任务或者抛弃前面的一些任务了。

  当这14个工人当中有人空闲时,而新任务增长的速度又比较缓慢,工厂主管可能就考虑辞掉4个临时工了,只保持原来的10个工人,毕竟请额外的工人是要花钱的。

  这个例子中的corePoolSize就是10,而maximumPoolSize就是14(10+4)。

  也就是说corePoolSize就是线程池大小,maximumPoolSize在我看来是线程池的一种补救措施,即任务量突然过大时的一种补救措施。

  不过为了方便理解,在本文后面还是将corePoolSize翻译成核心池大小。

  largestPoolSize只是一个用来起记录作用的变量,用来记录线程池中曾经有过的最大线程数目,跟线程池的容量没有任何关系。

<********************************************进源码里面see see*******************************************************************************>

    从ThreadPoolExecutor的入口方法execute开始吧,submit()也是封装下任务还是调用execute():

 public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

   贴上execute():

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
       
        int c = ctl.get();//读取ctl变量
        if (workerCountOf(c) < corePoolSize) {//当前线程数和corePoolSize比较,当小于时:
            if (addWorker(command, true)) //addWorker一个new thread来处理该任务(true的情况),直接返回;如果addWork返回false(线程池被shutdown or shutdownNow;或者同时又别的客户端提交任务,并且此时线程数大于corePoolSize);继续往下执行
                return;
            c = ctl.get();//重新读取ctl变量
        }
        if (isRunning(c) && workQueue.offer(command)) {//对addWorker返回false的情况进行判断,当线程池还运行着,说明是因为thread number 大于corePoolSize的情况,则&&操作第二个表达式把任务添加到workQueue队列//中.
            int recheck = ctl.get();//再次读取ctl,防止并发哦(可以看出j.u.c作者Doug lea的强大之处,不愧是并发的世界大牛,思维如此严谨)
            if (! isRunning(recheck) && remove(command)) //吧任务加入队列的同时,pool被shutdown, 则从队列中删除task,并且调用rejectHandler的方法
                reject(command);
            else if (workerCountOf(recheck) == 0) //如果此时线程数为0(即设置了allowCorePoolSizeTimeOut为true的情况),则追加一个new thread(初始任务为null)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))//对于其他addWorker()为false的情况,即!isRunning和workQueue.offer()失败的情况,再次尝试addWorker()添加new thread,如果为false,说明pool被关闭或者达到pool饱和,直接reject.
            reject(command);
    }

       注解中多次提到addWorker(),并且根据其返回true,false来进一步判断添加new thread成功或失败,说明其中也有判断pool状态的代码,为了完整性,先贴上reject()方法:

final void reject(Runnable command) {
        handler.rejectedExecution(command, this);//调用rejectHander的处理方法处理。
    }

       继续看一下addWorker(),在execute()中,两种带参数的addWorker(),addWorker(null, false),addWoker(command,false),addWorker(command,true);走完addWorker代码,再来具体讨论每一种意义:

 1   private boolean addWorker(Runnable firstTask, boolean core) {
 2         retry:
 3         for (;;) {
 4             int c = ctl.get();//添加new thread前,还是先读取pool ctl变量,判断一个pool state.
 5             int rs = runStateOf(c);
 6              //主要检测pool是否处于 >= shutdown 并且 (queue为空 || firstTask != null)的情况。
 8             if (rs >= SHUTDOWN &&       //!(rs == Shutdown && firstTask == null && ! workQueue.isEmpty()) == ( rs != shutdwon || fisrtTask != null || workQueue.isEmpty()) 
 9                 ! (rs == SHUTDOWN &&    //即条件为 rs >= shutdown && (rs != shutdown || firstTast != null || workQueue.isEmpty()),
10                    firstTask == null &&    //大概分三种情况吧: 1,rs >= shutdown && rs != shutdown .说明pool状态大于shutdown,即为stop ,terminate,tidiy,此时pool将停止等待执行的任务,和
//试着interrupt真正执行的任务所以没必要加入 new thread. 11 ! workQueue.isEmpty())) // 2: rs >= shutdown && firstTask,!= null .即为状态大于等于shutdown,客户端调用了shutdown(),并且此时新添加任务,拒绝false;对execute方法添加任务的二次检测
// 防止添加任务的同时,pool被shutdown.
12 return false; // 3: rs >= shutdown && workQueue.isEmpty(),即为状态大于等于shutdown,并且等待执行的任务为0,支持也么必要添加new thread了。 13 //其他组合方法大概也差不多, 14 for (;;) { //剩下来的情况为 1: pool state < shutdown(还运行着) 2 :shutdown状态,但queue不为空。 15 int wc = workerCountOf(c); //读取线程数。 16 if (wc >= CAPACITY || 17 wc >= (core ? corePoolSize : maximumPoolSize)) //如果线程数大于总大小限制2^29-1,或者根据core变量来判断是否大于 corePoolsize, maixmuPoolSize是否添加thread. 18 return false; 19 if (compareAndIncrementWorkerCount(c)) //cas操作,增加thread++成功,直接跳出外层循环;失败的话,说明ctl有改变,要么组成c的state变化,或thread number有变化 20 break retry; 21 c = ctl.get(); // ctl变化时,重新读取ctl值 22 if (runStateOf(c) != rs)//state变化时,重新从外部循环开始,重新判断pool状态,在来判断。 23 continue retry; 24 // 剩下cas操作失败由于thread number变化,重新内部循环,重新读取workerCount (思维严谨,完全体现在代码逻辑组织关系上,膜拜Doug lea) 25 } 26 } 27 //可以添加的thread的情况 28 boolean workerStarted = false; 29 boolean workerAdded = false; 30 Worker w = null; 31 try { 32 final ReentrantLock mainLock = this.mainLock; 33 w = new Worker(firstTask);//new thread的封装 34 final Thread t = w.thread; 35 if (t != null) { //判断threadFactory.newThread是否为null。 36 mainLock.lock(); 37 try { 38 41 int c = ctl.get(); //获得lock后,再次检查ctl state.防止获得mainLock之前,pool关闭, 42 int rs = runStateOf(c); 43 44 if (rs < SHUTDOWN || 45 (rs == SHUTDOWN && firstTask == null)) { 46 if (t.isAlive()) // 检查thread状态。 47 throw new IllegalThreadStateException(); 48 workers.add(w); 49 int s = workers.size(); 50 if (s > largestPoolSize)//更新线程池最大线程数 51 largestPoolSize = s; 52 workerAdded = true; //添加成功标志 53 } 54 } finally { 55 mainLock.unlock(); 56 } 57 if (workerAdded) { 58 t.start();//此时有可能出现OOM异常,workerStart将得不到true赋值。 59 workerStarted = true; 60 } 61 } 62 } finally { 63 if (! workerStarted) //如果出现为false,OOM异常,或者ThreadFactory返回null thread, 64 addWorkerFailed(w); //清理worker工作 65 } 66 return workerStarted; 67 }

      现在来看看execute出现三种addWorker. 1:addWorkder(command,true),以command(runnable)为参数创建Worker,并以command为初始执行的任务,true参数为 根据corePoolSize参数判断是否添加new worker。

2:addWorker(null, false),实在workercountOf() == 0情况下添加一个初始任务为null的worker来执行刚添加到队列中的任务(可能出现添加任务时,一个线程刚死掉timeOut了) 3:addWorker(command,false),是在添加task到队列中失败时,通过addWorker来判断,如果失败,说明pool shutdown或者超容量了。

      

  public void shutdown() {
        final ReentrantLock mainLock = this.mainLock; //在addWorker中也是通过mainLock开锁定,来实现添加线程和shutdown同步互斥的。
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); 
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

     Worker添加失败的清理工作:

   private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (w != null)
                workers.remove(w);//清除hashset<worker>中的该工作worker.
            decrementWorkerCount();//workerCount--.
            tryTerminate();//检查是否pool termination,防止该worker中有terminate操作。
        } finally {
            mainLock.unlock();
        }
    }
final void tryTerminate() {
        for (;;) { //转到terminated状态的两种情况(1:shutdown状态,queue空,pool空; 2:STOP状态,pool空)
            int c = ctl.get();
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) //1:当处于running状态直接返回,不可能有转向terminated的趋势, 2: 状态至少为TIDYING,此时就差terminated()方法调用或者
                return;                                         //已经处于terminated状态直接返回, 3:处于shutdown,并且队列不为空,还得执行队列中的任务呢,返回。
            if (workerCountOf(c) != 0) { // 到这步指的哪些 shutdown & queue.isEmpty() & pool(workerCounter) != 0 和 stop状态 & pool != 0的情况,(这两有转往terminated状态的趋势,只要kill workerHashSet)
                interruptIdleWorkers(ONLY_ONE);//一个个的清除空闲线程
                return;
            }
            //到这里就是上面指的 (shutdown & queue.isEmpty() & workerCounter == 0) || (stop & workerCounter == 0)的情况 
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { //置于TIDYING状态(ctl值)
                    try {
                        terminated();//调用terminated(),转向terminated状态
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();//通知哪些阻塞awaitTerminate()方法客户端。
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // 上面cas设置ctl的TIDYING状态时失败,for循环操作。
        }
    }

    漂亮的cas失败重试操作,再来看看Worker的代码:

 private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable  //AQS以后在分析,实现runnable.
    {
    
        volatile long completedTasks;//Worker完成的task数量,用于线程池统计。

        Worker(Runnable firstTask) {
            setState(-1); //初始状态 -1,防止在调用runWorker(),也就是真正执行task前中断thread。
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);//thread封装
        }

        public void run() {
            runWorker(this);//实际的task操作,调用thread pool的loop操作,有初始task,先干它,然后在不断循环取队列中task干。
        }
 
//0 代表无锁状态, 1:上锁状态 AQS方法。
protected boolean isHeldExclusively() { return getState() != 0; } //底下一些阻塞,非阻塞上锁,去锁操作 protected boolean tryAcquire(int unused) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } protected boolean tryRelease(int unused) { setExclusiveOwnerThread(null); setState(0); return true; } public void lock() { acquire(1); } public boolean tryLock() { return tryAcquire(1); } public void unlock() { release(1); } public boolean isLocked() { return isHeldExclusively(); } //用于shutdownNow,中断当前真在执行的线程,(-1状态下不可中断) void interruptIfStarted() { Thread t; if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { try { t.interrupt(); } catch (SecurityException ignore) { } } } }

     既然addWorker中start了Worker,就继续看看真在的run()中的runWork()吧:

 final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); //允许中断了
        boolean completedAbruptly = true;//是否在task运行过程有异常.
        try {
            while (task != null || (task = getTask()) != null) {//loop 初始task不为null,先执行初始task,执行完在loop在队列中去task来执行
                w.lock();//该锁,用于识别该worker是否为idle worker,当lock时,说明该worker真在干活呢,不是idle,和interruptIdleWorkers(boolean)相呼应,interrupt idle worker时,会尝试tryLock().
                if ((runStateAtLeast(ctl.get(), STOP) || // 1: 当pool处于STOP或者更高状态时,确保该线程被interrupted.  
                     (Thread.interrupted() &&            // 2: 当pool处于STOP之下的状态时,确保该thread没有被中断。a: 当第一个runStateAtLeast(Stop)返会true,直接跳到!wt.isInterrupted()来判断
                      runStateAtLeast(ctl.get(), STOP))) &&    //是否中断过,如果为中断过,结果为false,直接跳过; b:当没有中断过,返回true,中断该线程; c: 当第一个runstateAtLeast(stop)为false时,即
                    !wt.isInterrupted())                       //state < stop,未执行的任务得照常执行,执行|| 后面的(),条件2说了确保处于running 或shutdown状态下,确保该线程未被interrupt过(为什么得
                    wt.interrupt();                            // 确保执行线程未被中断过呢,因为shutdownNow()方法调用时会尝试interruptIfStart()方法,而该方法interrupt条件其中之一为!t.isInterrupted
                try {                                          // ,就是说如果shutdownNow调用时,真正运行的thread的interrpt标志已经存在,则不会中断真在运行的thread.那什么东西给线程设置的interrupt标志呢?
                    beforeExecute(wt, task);                  //大概也许貌似是Future.cancel()。)
                    Throwable thrown = null;                  
                    try {                                      //beforeExecute(),afterExecute()可以在task执行前后做一些工作,例如统计,日志什么的,看你心情。但如果beforeExecute中throw出异常的话,
                        task.run();                            //可以导致thread game over die的,并且task并不会执行,此时的complectedAbruptly 为true,标志死的太突然,
                    } catch (RuntimeException x) {             //task执行可能会跑出异常,三种封装交给Thread.uncaughtedExceptionHandler处理,
                        thrown = x; throw x;                   //afterExecute也能抛出异常,导致thread die。 task的异常(有的话)会交给afterExecute,所以可以做一些记录啊什么的。
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;// 统计工作
                    w.unlock();
                }
            }
            completedAbruptly = false;  //这里有退出方式 1:beforeExecute,afterExecute, task run时throw execption, 这几种死法对应completedAbruptly 为true.
        } finally {                     //   2:getTask() == null ,退出while loop,此时 completedAbruptly为false. 不同的死法对应了底下processWorkerExit()不同的处理。
            processWorkerExit(w, completedAbruptly);
        }
    }

       接着看getTask():

 private Runnable getTask() {
        boolean timedOut = false; //该标签loop嵌套循环,用于标志是否在blockingQueue等待超时。 
        retry:
        for (;;) {
            int c = ctl.get(); 
            int rs = runStateOf(c);

           // 检测state是否大于等于STOP,或者SHUTDWON & taskQueue.isEMpty().这两种可以就清场,不干活了。
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount(); //如果是的话,该thread 准备死了,cas操作,失败loop重试,减小workerCount,为它死做好铺垫嘛。
                return null;
            }

            boolean timed;      //是否有多余corePoolSize的thread,或者allowCorePoolSize,则为true(== 0) 

            for (;;) {
                int wc = workerCountOf(c); 
                timed = allowCoreThreadTimeOut || wc > corePoolSize;

                if (wc <= maximumPoolSize && ! (timedOut && timed))    // wc <= maximunPoolSize && (! timedOut || ! timed) 即线程数大于maxiumPoolSize,或者在keepAlive时间内没得到task,并且
                    break;                                             //timed为true(即有多余的线程),则该线程准备也死了; 否则跳出内部循环去等待task.
                if (compareAndDecrementWorkerCount(c)) //cas操作,失败loop重试
                    return null; 返回null
                c = ctl.get();   
                if (runStateOf(c) != rs) //状态改变,外部循环重新开始
                    continue retry;
//workerCounter的改变,内部loop。
} try { Runnable r = timed ? //如果有多余的线程(即workercounter > corepoolSize 或者allowCorePoolSizeTimeOut),则等待keepAlive时间返回。好让他们没task时,去死嘛!,否则即wc <= corePoolSize & workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // allowCorePoolTimeOut 为false ,则一直阻塞下去,知道有task. workQueue.take(); if (r != null) return r; timedOut = true; } catch (InterruptedException retry) { timedOut = false; } } }

      在来看看该死的thread的清场:

  private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // 如果死的突然,即task执行 begin,执行中和,after有异常。
            decrementWorkerCount(); //workerCounter --.

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;//统计工作
            workers.remove(w);//移除尸体
        } finally {
            mainLock.unlock();
        }

        tryTerminate(); //检查terminated状态的趋势。

        int c = ctl.get();
        if (runStateLessThan(c, STOP)) { //状态判断 ,小于STOP,等待的task还是得运行的。
            if (!completedAbruptly) { //不是异常死的
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize; // 检查系统最低线程数,1:allowCoreThreadTimeout, 最低为0 ,2: 为false,最低为corePoolSize,
                if (min == 0 && ! workQueue.isEmpty()) //allowCoreThreadTimeOut为true, 如果队列不为空,最小为1,(人家还有task要做,又不stop状态,好歹给人家一个线程运行啊) 
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // workercounter > min的话,没必须补充能量
            }
            addWorker(null, false); //补充线程(无初始任务的)来执行队列中的任务
        }
    }

     至此线程池大体流程以结束。

    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(STOP);
            interruptWorkers();//中断所有线程啊???
            tasks = drainQueue();//提取队列中的任务,返回
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }
   private void interruptWorkers() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers)
                w.interruptIfStarted();//worker的方法,即运行了才interrupt.
        } finally {
            mainLock.unlock();
        }
    }
 public boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (;;) {
                if (runStateAtLeast(ctl.get(), TERMINATED)) //条件判断,不是一下子就闭着眼睛就去阻塞等待
                    return true;
                if (nanos <= 0)
                    return false;
                nanos = termination.awaitNanos(nanos); //等待,signalAll来拯救
            }
        } finally {
            mainLock.unlock();
        }
    }

    大体完毕,谢谢!

 参考:http://www.cnblogs.com/dolphin0520/p/3932921.html

         http://www.blogjava.net/xylz/archive/2010/12/19/341098.html

 

J.U.C ThreadPoolExecutor解析

标签:

原文地址:http://www.cnblogs.com/onlysun/p/4603200.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!