线程池的原码分析(一)

一、线程的生命周期

线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、销毁。

  新建:就是刚使用new方法,new出来的线程;

  就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;

  运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;

  阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态;

  销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;

 二、线程池的种类

  1. Executors.newCachedThreadPool();
    说明: 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程.
    内部实现:new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue());

  2. Executors.newFixedThreadPool(int);
    说明: 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    内部实现:new ThreadPoolExecutor(nThreads, nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue());

  3. Executors.newSingleThreadExecutor();
    说明:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照顺序执行。
    内部实现:new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue())

  4. Executors.newScheduledThreadPool(int);
    说明:创建一个定长线程池,支持定时及周期性任务执行。
    内部实现:new ScheduledThreadPoolExecutor(corePoolSize)

   public ScheduledThreadPoolExecutor(int corePoolSize) {
          super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
      }

正常开发中不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

说明: Executors 返回的线程池对象的弊端如下:
  1) FixedThreadPool 和 SingleThreadPool:
    允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
  2) CachedThreadPool 和 ScheduledThreadPool:
    允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程,从而导致 OOM。

三、ThreadPoolExecutor

1、线程池创建使用示例代码:

    public void test7(){
        //初始化线程池
        ExecutorService executor = new ThreadPoolExecutor(10, 20, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(50));
        //调用线程执行任务
        executor.execute(()->{
            //do something
        });
    }
    //构造器
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
    //构造器
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

核心参数说明 

参数说明
corePoolSize 核心线程数量,线程池维护线程的最少数量
maximumPoolSize 线程池维护线程的最大数量
keepAliveTime 线程池除核心线程外的其他线程的最长空闲时间,超过该时间的空闲线程会被销毁
unit keepAliveTime的单位,TimeUnit中的几个静态属性:NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS
workQueue 线程池所使用的任务缓冲队列
threadFactory 线程工厂,用于创建线程,一般用默认的即可
handler 线程池对拒绝任务的处理策略

2、关系类图

ThreadPoolExecutor继承了AbstractExecutorService,AbstractExecutorService实现了ExecutorService接口,ExecutorService继承了Executor接口

2.1 Executor

public interface Executor {
    void execute(Runnable command);
}

只有一个方法execute,是java线程池最核心的方法。返回类型是void,这个方法入参是一个runnable的实例,代表提交一个线程任务。

2.2 ExecutorService

public interface ExecutorService extends Executor {
 
    // 关闭线程池,不接受新的任务。但是这个方法并不会终止正在执行的任务
    void shutdown();
 
    // 也是关闭线程池,不接受新的任务。但是这个方法会停止所有正在执行的任务
    List<Runnable> shutdownNow();
 
    // 判断线程池是否已经被关闭
    boolean isShutdown();
 
    // 调用shutDown或者shutDownNow后,如果所有任务都完成了,返回true,否则返回false
    boolean isTerminated();
 
    /**
     * 调用这个方法会等待所有任务完成,并且指定了等待的超时时间,返回是否等待超时。
     * 不论是调用shutDown还是shutDownNow,都不会等待任务结束。
     * 所以我们应该是先调用shutDown/shutDownNow,再调用此方法等待所有任务完成
     */
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
 
    // 提交一个任务,不同于execute方法,这里的入参是callable,并且返回值是Future
    <T> Future<T> submit(Callable<T> task);
 
    /**
     * 提交一个任务,但是这里的任务是runnable,
     * runnable执行run后是无返回值的,所以这里传入的result直接作为返回值。
     */
    <T> Future<T> submit(Runnable task, T result);
 
    // 提交一个runnable任务
    Future<?> submit(Runnable task);
 
    // 执行传入的所有的任务
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;
 
    // 执行的传入的所有任务,并指定超时时间
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;
 
    // 执行传入的所有任务,只要其中一个任务完成这个方法就可以返回了,返回这个任务的执行结果
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;
 
    // 同上一个方法,只不过这个方法指定了超时时间
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

从这里我们看到,线程池提交任务的方法有execute和submit,submit和execute最大区别在于submit方法可以获取到线程的执行结果。

submit的入参可以是Runnable,也可以是Callable,实现原理请看下图及源码

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        //将task包装成RunnableFuture
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);。
        return ftask;
    }
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        //返回一个FutureTask
        return new FutureTask<T>(runnable, value);
    }
    public FutureTask(Runnable runnable, V result) {
        //将Runnable包装成Callable
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        //这里使用到了适配器
        return new RunnableAdapter<T>(task, result);
    }
    static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }

我们看到FutureTask实现了RunnableFuture,而RunnableFuture继承了Runnable和Future,接下来我们来研究一下FutureTask。

2.3 FutureTask

2.3.1 task的状态定义

     /*
     * 可能的状态变更:
     * NEW -> COMPLETING -> NORMAL
     * NEW -> COMPLETING -> EXCEPTIONAL
     * NEW -> CANCELLED
     * NEW -> INTERRUPTING -> INTERRUPTED
     */
    private volatile int state;
    private static final int NEW          = 0; //初始状态
    private static final int COMPLETING   = 1; //结果计算完成或响应中断到赋值给返回值之间的状态
    private static final int NORMAL       = 2; //任务正常完成的状态,结果被set
    private static final int EXCEPTIONAL  = 3; //任务抛出异常
    private static final int CANCELLED    = 4; //已取消
    private static final int INTERRUPTING = 5; //线程中断状态被设置ture,但线程未响应中断
    private static final int INTERRUPTED  = 6; //已中断

详细解释如下

  NEW:表示是个新的任务或者还没被执行完的任务。这是初始状态。
  COMPLETING:任务已经执行完成或者执行任务的时候发生异常,但是任务执行结果或者异常原因还没有保存到outcome字段(outcome字段用来保存任务执行结果,如果发生异常,则用来保存异常原因)的时候,状态会从NEW变更到COMPLETING。但是这个状态会时间会比较短,属于中间状态。
  NORMAL:任务已经执行完成并且任务执行结果已经保存到outcome字段,状态会从COMPLETING转换到NORMAL。这是一个最终态。
  EXCEPTIONAL:任务执行发生异常并且异常原因已经保存到outcome字段中后,状态会从COMPLETING转换到EXCEPTIONAL。这是一个最终态。
  CANCELLED:任务还没开始执行或者已经开始执行但是还没有执行完成的时候,用户调用了cancel(false)方法取消任务且不中断任务执行线程,这个时候状态会从NEW转化为CANCELLED状态。这是一个最终态。
  INTERRUPTING:任务还没开始执行或者已经执行但是还没有执行完成的时候,用户调用了cancel(true)方法取消任务并且要中断任务执行线程但是还没有中断任务执行线程之前,状态会从NEW转化为INTERRUPTING。这是一个中间状态。
  INTERRUPTED:调用interrupt()中断任务执行线程之后状态会从INTERRUPTING转换到INTERRUPTED。这是一个最终态。
有一点需要注意的是,所有值大于COMPLETING的状态都表示任务已经执行完成(任务正常执行完成,任务执行异常或者任务被取消)。

2.3.2 成员变量

volatile int state:就是当前task的状态,含NEW、COMPLETING等
/** The underlying callable; nulled out after running */
Callable<V> callable:将要执行的任务,调用完后,会被赋值为null
/** The result to return or exception to throw from get() */
Object outcome:用于get()返回的结果,也可能是用于get()方法抛出的异常
/** The thread running the callable; CASed during run() */
volatile Thread runner:执行callable的线程,调用FutureTask.run()方法通过CAS设置
/** Treiber stack of waiting threads */
volatile WaitNode waiters:无锁并发栈结构的等待线程队列
// Unsafe mechanics
UNSAFE:可直接操作内存的类。
static final long runnerOffset:UNSAFE使用的,runner成员变量在FutureTask类中的偏移量
static final long stateOffset:UNSAFE使用的,state成员变量在FutureTask类中的偏移量
static final long waitersOffset:UNSAFE使用的,waiters成员变量在FutureTask类中的偏移量

2.3.3 run()方法

    public void run() {
        //如果状态不是new,则说明该task已经执行过了(state>0),就不需要再次执行了
        //如果状态为new,则尝试把当前线程赋值给runnerOffset,如果赋值失败,只能返回
        //保证callable任务只被运行一次
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    //1、调用callable.call(),执行task
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    //2、抛出异常则设置异常
                    setException(ex);
                }
                if (ran)
                    //3、正常返回值设置
                    set(result);
            }
        } finally {
            //
            runner = null;
            //
            int s = state;
            //任务处于中断中的状态,则进行中断操作
            if (s >= INTERRUPTING)
          //4、处理中断的情况 handlePossibleCancellationInterrupt(s); } }

step2:抛出异常设置异常对象

    protected void setException(Throwable t) {
        //将状态位设置成中间状态COMPLETING
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            //设置输出的为异常信息
            outcome = t;
            //将状态更为最终状态EXCEPTIONAL
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
            //由中间状态到最终状态变更时,都需进行的操作
            finishCompletion();
        }
    }

执行完成的后置方法

    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            //尝试将waiters全部置为null
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                //将waiters下对应的链式thread挨个唤醒
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        //唤醒操作,LockSupport.park()阻塞
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
     //空实现
        done();
        callable = null;        // to reduce footprint
    }

step3:正常返回时,设置值

    protected void set(V v) {
        //将状态位设置成中间状态COMPLETING
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            //设置输出为正常返回结果
            outcome = v;
            // 将状态更为最终状态NORMAL
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            //执行完成的后置方法
            finishCompletion();
        }
    }

step4、处理中断的情况

   //确保cancel(true)产生的中断发生在run或runAndReset方法过程中。 
    private void handlePossibleCancellationInterrupt(int s) {
        if (s == INTERRUPTING)
            while (state == INTERRUPTING)
                // 让出cpu时间片,等待cancel(true)执行完成,此时INTERRUPTING必然能更成INTERRUPTED
                Thread.yield(); // wait out pending interrupt
    }

2.3.4 runAndReset() 方法,周期性执行,每次正常执行完后状态依然是New

    protected boolean runAndReset() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return false;
        boolean ran = false;
        int s = state;
        try {
            Callable<V> c = callable;
            if (c != null && s == NEW) {
                try {
                    // 与run()相比,少了设置返回结果,以及状态变更
                    c.call(); // don't set result
                    ran = true;
                } catch (Throwable ex) {
                    //设置异常
                    setException(ex);
                }
            }
        } finally {
            runner = null;
            s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
        //判断执行完后是否重置成功
        return ran && s == NEW;
    }

 2.3.5 get()方法,获取task的执行结果

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            //如果是中间状态,则等待task完成
            s = awaitDone(false, 0L);
     //返回结果
return report(s); }

等待task完成

    //等待完成 可能是是中断、异常、正常完成,timed:true,考虑等待时长,false:不考虑等待时长
    private int awaitDone(boolean timed, long nanos) throws InterruptedException {
        //计算超时时间
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            //1、如果线程已中断,则直接将当前节点q从waiters中移出 并抛出中断异常
            if (Thread.interrupted()) {
          //移除节点 removeWaiter(q);
throw new InterruptedException(); } int s = state; //2、如果state已经是最终状态了,则直接返回state if (s > COMPLETING) { //上面q赋的初值就是null if (q != null) q.thread = null; return s; } //3、如果state是中间状态(COMPLETING),意味很快将变更为最终状态,让出cpu时间片等待即可 else if (s == COMPLETING) Thread.yield(); //4、如果发现尚未有节点,则创建节点 else if (q == null) q = new WaitNode(); //5、如果当前节点尚未入队,则将当前节点放到waiters中的首节点,并替换旧的waiters else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q); //6、线程被阻塞指定时间后再唤醒 else if (timed) { nanos = deadline - System.nanoTime(); //超出等待时间,从waiters中移出节点q,返回节点状态 if (nanos <= 0L) {
            //移除节点 removeWaiter(q);
return state; } LockSupport.parkNanos(this, nanos); } //7、线程一直被阻塞直到被其他线程唤醒 else LockSupport.park(this); } }

等待节点WaitNode的结构

    //栈结构的Thread
    static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }

移除节点

    //移除节点
    private void removeWaiter(WaitNode node) {
        if (node != null) {
            //将需要去除的节点,thread赋值为null
            node.thread = null;
            retry:
            for (;;) {          // restart on removeWaiter race
                //定义一个前节点pred为null,把属性waiters赋给q,定义一个节点s,在每次循环后把s赋给q,退出循环的条件是q不为null
                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                    //把q的下一个节点赋值给s
                    s = q.next;
                    //如果q的thread不为null,表示不是要移除的节点
                    if (q.thread != null)
                        //把q赋给pred
                        pred = q;
                    //如果q.thread==null,表示该节点是需要在队列中去除的节点,判断前一个节点是否为null,不为null直接将
                    //s赋给pred.next,此刻的s就是q的下个节点,重组队列
                    else if (pred != null) {
                        pred.next = s;
                        //要检查线程竞争的情况,如果前一个节点的线程也是null的则继续循环
                        if (pred.thread == null) // check for race
                            continue retry;
                    }
                    //如果q.thread==null并且pred == null 通过cas把s赋给当前waiters属性 继续循环
                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                          q, s))
                        continue retry;
                }
                break;
            }
        }
    }

返回结果

    @SuppressWarnings("unchecked")
    private V report(int s) throws ExecutionException {
        //outcome是在run方法里进行的赋值,现在赋给x返回
        Object x = outcome;
        if (s == NORMAL)
            return (V)x;
        if (s >= CANCELLED)
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }

2.3.6 含超时时间的取值过程

    public V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            //状态小于1,并且超出等待时间 抛出异常
            throw new TimeoutException();
        return report(s);
    }

2.3.7 cancel(boolean) 取消task,根据boolean值来决定是否可进行中断操作

    public boolean cancel(boolean mayInterruptIfRunning) {
        //如果状态不为NEW,且无法将状态更新为INTERRUPTING或CANCELLED,则直接返回取消失败
        if (!(state == NEW &&
              UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            //运行中允许进行 中断操作
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                        //并不是实时取消!
                        t.interrupt();
                } finally { // final state
                    //中断成功,则置为最终状态
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }

2.3.8 其他的一些方法

    //判断是否取消成功
    public boolean isCancelled() {
        return state >= CANCELLED;
    }
    //判断任务是否完成
    public boolean isDone() {
        return state != NEW;
    }
    //扩展使用 暂无实现
    protected void done() { }

总结:

  submit方法之所以可以获取线程执行结果,全依赖于callable和FutureTask。FutureTask实现了Runnable的run方法,在run方法中会调用callable.call()获取执行结果,并将执行结果就存储在FutureTask中。

  调用submit方法的时候,直接将callable/runnable对象包装成FutureTask,然后调用FutureTask.run(),最终返回FutureTask对象。我们调用FutureTask.get()就可以阻塞获取到线程的执行结果了。

2.4 AbstractExecutorService,ExecutorService的抽象实现类

public abstract class AbstractExecutorService implements ExecutorService {
   // 创建任务
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
   // 创建任务
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }
   // 提交任务
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
   // 提交任务
    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;
    }
   // 提交任务
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        // 任务交给子类执行
        execute(ftask);
        return ftask;
    }
    
    //将collection中的任务提交给线程池执行,只要有一个任务完成,这个方法就可以返回了
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException {
        try {
            return doInvokeAny(tasks, false, 0);
        } catch (TimeoutException cannotHappen) {
            assert false;
            return null;
        }
    }
    // 带超时时间的
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                           long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        return doInvokeAny(tasks, true, unit.toNanos(timeout));
    }

    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                              boolean timed, long nanos)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (tasks == null)
            throw new NullPointerException();
        // 获取集合中任务的数量
        int ntasks = tasks.size();
        if (ntasks == 0)
            // 没有任务抛出异常
            throw new IllegalArgumentException();
        // 用Future来包装任务
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
        // ExecutorCompletionService这个类的构造方法传入了this作为真正的Executor
        // 这个方法会在每个任务完成后,把被FutureTask包装好的callable任务保存到一个LinkedBlokingQueue中
        ExecutorCompletionService<T> ecs =
            new ExecutorCompletionService<T>(this);

        try {
            // 记录异常,这样如果我们无法获得任何结果,我们就可以抛出我们得到的最后一个异常。
            ExecutionException ee = null;
            // 计算超时时长
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
             // 迭代所有的callable任务
            Iterator<? extends Callable<T>> it = tasks.iterator();
// 这里调用了ecs.submit提交一个任务给线程池,并且将封装每个任务的FutureTask保存在futures中
            futures.add(ecs.submit(it.next()));
            // 任务数-1
            --ntasks;
            // 从名字都可以看出来,这个代表正在执行的任务数
            int active = 1;

            for (;;) {
                // 我们上面说ExecutorCompletionService中有个LinkedBlockingQueue用于保存每个任务的FutureTask。
                // 那么这里调用poll方法尝试将FutureTask取出来,这里的poll方法是非阻塞的
                Future<T> f = ecs.poll();
                // 如果f为null,说明前面提交的任务还没执行完成。
                if (f == null) {
                    // 我们说这个方法只要有一个任务执行完成就返回了,
                    // 现在还没有任务执行完成,那么接着执行后面的任务
                    if (ntasks > 0) {
                        --ntasks;
                        futures.add(ecs.submit(it.next()));
                        ++active;
                    }
                    // 如果这里的active为0,说明所有的任务都执行完了(不一定是执行成功了),从这里break出去
                    else if (active == 0)
                        break;
                    // 进入这个分支说明已经没有任务了  判断是否需要检测超时
                    else if (timed) {
                        // 再poll一次,如果为null 抛出超时异常
                        f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                        if (f == null)
                            throw new TimeoutException();
                        nanos = deadline - System.nanoTime();
                    }
                    else
                    // 到这一步说明已经没有任务了,也没有设置超时,
                    // 那么调用take方法阻塞,直到有任务执行完成
                        f = ecs.take();
                }
                // 如果f!=null说明有任务执行完成了
                if (f != null) {
                     // 正在执行的任务数-1
                    --active;
                    try {
                        // 调用FutureTask.get()阻塞等待执行结果并返回结果
                        return f.get();
                    } catch (ExecutionException eex) {
                        ee = eex;
                    } catch (RuntimeException rex) {
                        ee = new ExecutionException(rex);
                    }
                }
            }

            if (ee == null)
                ee = new ExecutionException();
            throw ee;

        } finally {
            // 最后在return之前,取消其他还没结束的任务
            for (int i = 0, size = futures.size(); i < size; i++)
                futures.get(i).cancel(true);
        }
    }
    
    // 这个方法就是提交collection中所有的callable任务,并返回结果列表
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        // 使用Future包装任务
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        // 任务是否完成的标志位
        boolean done = false;
        try {
            for (Callable<T> t : tasks) {
                 // 将所有的callable任务包装成FutureTask
                RunnableFuture<T> f = newTaskFor(t);
                // 将所有的FutureTask保存到futures这个List中
                futures.add(f);
                // 提交任务
                execute(f);
            }
            // 循环遍历所有的FutureTask
            for (int i = 0, size = futures.size(); i < size; i++) {
                Future<T> f = futures.get(i);
                // 如果这个任务还没完成
                if (!f.isDone()) {
                    try {
                        // 调用FutureTask.get()阻塞,直到任务完成获取到值
                        f.get();
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    }
                }
            }
            // 代表所有任务都已执行完成
            done = true;
            // 返回FutureTask的List列表
            return futures;
        } finally {
            // 如果!done,说明有任务没完成,就是说try中代码出现了异常,取消任务
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }
    //相对于上面的增加了超时机制
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                         long timeout, TimeUnit unit)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        long nanos = unit.toNanos(timeout);
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks)
                futures.add(newTaskFor(t));
            //计算超时时间线
            final long deadline = System.nanoTime() + nanos;
            final int size = futures.size();

            // Interleave time checks and calls to execute in case
            // executor doesn't have any/much parallelism.
            for (int i = 0; i < size; i++) {
                execute((Runnable)futures.get(i));
                nanos = deadline - System.nanoTime();
                // 每个线程提交后判断一下超时
                if (nanos <= 0L)
                    return futures;
            }

            for (int i = 0; i < size; i++) {
                Future<T> f = futures.get(i);
                if (!f.isDone()) {
                    // 先判断一下是否超时
                    if (nanos <= 0L)
                        return futures;
                    try {
                        f.get(nanos, TimeUnit.NANOSECONDS);
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    } catch (TimeoutException toe) {
                        return futures;
                    }
                    nanos = deadline - System.nanoTime();
                }
            }
            done = true;
            return futures;
        } finally {
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }

}

2.5  ThreadPoolExecutor

  啊,太长了下一篇接着讲吧。

参考:https://blog.csdn.net/Epoch_Elysian/article/details/107282186

posted @ 2021-09-15 15:12  上官兰夏  阅读(102)  评论(0)    收藏  举报