AbstractExcutorService源码分析

  1. submit方法
    	// submit方法1: 参数为任务方法体Runnable
    	public Future<?> submit(Runnable task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<Void> ftask = newTaskFor(task, null);
            execute(ftask);
            return ftask;
    	}
    	// submit方法2: 参数为任务方法体Runnable, 结果T
    	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;
        }
    	// submit方法3: 参数为任务方法体Callable
    	public <T> Future<T> submit(Callable<T> task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<T> ftask = newTaskFor(task);
            execute(ftask);
            return ftask;
        }
    /**
     * 执行逻辑:
     * 都是创建的newTaskFor(FutureTask) 将任务传递到FutureTask中, 来处理任务的。
     * 调用execute方法执行任务。
     * 返回结果。
     */
     /**
      * 区别:
      * 区别主要在参数与获取返回值的方式。
      * 参数包含Runnable都是通过newTaskFor(task, null);创建任务FutureTask, 第一个参数时Runnable, 第二个参数是其返回的结果。
      * 参数是Callable是通过newTaskFor(Callable);创建的任务FutureTask。
      * 无论那种方式, 其实际都是创建了一个带有Callable属性的FutureTask任务对象。通过FutureTask来执行具体的任务, 实际执行逻辑就是Callable的call方法。
      * 如果参数是Callable, 那么创建的FutureTask的Callable属性就是参数Callable对象; 如果参数是Runnable那么就会通过Executors.callable(runnable, result);
      * 来构建Callable对象, 通过构建的Callable来创建FutureTask对象。
      * 所以三种方法的返回值也比较清楚了, 方法1, 只有Runnable, 没有传入返回值, 通过传入null作为结果, 构建Callable, 所以通过submit返回值Future对象的get方法获取返回值时,
      * 返回的就是null, 无论run方法体是如何执行的。方法2, 参数为Runnable和T result, 那么Callable的call方法就是Runnable的run方法, Callable的返回值就是T result。也就是说,
      * 先执行任务逻辑run方法, 再直接将T result作为返回值返回。所以无论run方法如何执行, 返回的都是result。所以调用get方法获取返回值时,返回的就是result。
      * 方法1和方法2类似, 都是将第二个参数作为返回值。方法3, 直接传入的Callable, 直接使用其创建FutureTask。那么任务逻辑就是call方法, 返回值就是Callable的返回值。
      */
     /**
      * Runnable参数时, 如何构建Callable对象:
      * submit中使用newTaskFor创建一个FutureTask对象。
      * 如果传入的是Callable那么调用FutureTask的构造方法new FutureTask(Callable)创建。
      * 如果传入的是Runnable那么通过调用FutureTask的构造方法FutureTask<T>(runnable, value);该构造方法通过Executors.callable(runnable, result);创建Callable
      * 作为FutureTask的Callable属性。Executors.callable(runnable, result);创建内部类RunnableAdapter, 将Runnable转换成Callable。
      */


     

  2. invokeAll方法:
     

    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
            throws InterruptedException {
            if (tasks == null)
                throw new NullPointerException();
        // 结果集合, 存放所有任务的结果。越先执行完成的任务, 结果越往前。
            ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        // 所有任务是否全部完成
            boolean done = false;
            try {
                for (Callable<T> t : tasks) {
                    // 创建任务FutureTask(实现RunnableFuture),并且执行任务
                    RunnableFuture<T> f = newTaskFor(t);
                    futures.add(f);
                    // 调用父类ExecutorService的方法,具体执行逻辑由子类实现
                    execute(f);
                }
                // 遍历结果队列,判断是否所有任务全部成功执行
                for (int i = 0, size = futures.size(); i < size; i++) {
                    Future<T> f = futures.get(i);
                    if (!f.isDone()) {
                        try {
                            // 等待任务执行完成。
                            f.get();
                        } catch (CancellationException ignore) {
                        } catch (ExecutionException ignore) {
                        }
                    }
                }
                done = true;
                return futures;
            } finally {
                // 如果出现异常,导致没有全部执行成功,取消未执行完成的任务。
                if (!done)
                    for (int i = 0, size = futures.size(); i < size; i++)
                        futures.get(i).cancel(true);
            }
        }


     

  3. invokeAll方法(带超时时间):
     

    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);
        	// 创建任务队列,Future集合
            ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
            boolean done = false;
            try {
                // 先将所有任务转换成FutureTask(实现了RunnableFuture),并且添加到任务队列中。
                // 将添加任务队列操作和只执行操作分开的原因是因为是纳秒级别的,所有new,add等操作也是耗费时间的,
                // 分开操作是为了更精准的计算超时时间。
                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);
            }
        }


     

  4. invokeAny
     

    // 某个任务执行完成后返回结果
    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));
    }


     

  5. doInvokeAny方法
     

    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();
            ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
        	/**
             * 这里使用ExecutorCompletionService的作用。
             * 代理线程池去执行任务,当任务执行完后,将执行结果加入到队列中,供外部判断是否存在任务已完成。
             * 首先,ExecutorCompletionService是用来提交执行任务的。ExecutorCompletionService中定义了一个Executor,
             * 他用来执行一个任务,具体的执行逻辑由子类实现。执行逻辑,将任务提交(submit)给ExecutorCompletionService(简称ecs),
             * 首先ecs会将任务进行封装,封装成ecs的内部类QueueingFuture,QueueingFuture继承了FutureTask,使任务完成具有返回值,
             * 并且QueueingFuture重写了FutureTask的done方法,done方法是一个回调方法,也就是说,当任务执行完成时,会自动调用done方法,
             * 而QueueingFuture重写done方法,在任务执行完成时将任务的返回值Future加入队列BlockingQueue(ExecutorCompletionService
             * 定义的一个属性)。没完成一个任务就会加入一个结果Future到BlockingQueue中,顺序就是任务完成时的顺序。那么在doInvokeAny方法
             * 中,死循环中不断判断是否有任务已经完成,只要调用ExecutorCompletionService的poll方法即可。poll方法就是从BlockingQueue中
             * 取出第一个元素,如果取到,那么证明有任务完成,那么doInvokeAny就可以返回了(完成了任意一个任务)。如果返回的是null那么证明
             * 还没有任务执行完成,继续循环判断。其中poll方法是调用BlockingQueue的poll方法,在ExecutorCompletionService中
             * BlockingQueue是通过LinkedBlockingQueue实现的。
             */
            ExecutorCompletionService<T> ecs =
                new ExecutorCompletionService<T>(this);
    
            // For efficiency, especially in executors with limited
            // parallelism, check to see if previously submitted tasks are
            // done before submitting more of them. This interleaving
            // plus the exception mechanics account for messiness of main
            // loop.
    
            try {
                // Record exceptions so that if we fail to obtain any
                // result, we can throw the last exception we got.
                ExecutionException ee = null;
                // 计算超时时间
                final long deadline = timed ? System.nanoTime() + nanos : 0L;
                // 任务队列的迭代器, 遍历所有任务
                Iterator<? extends Callable<T>> it = tasks.iterator();
    
                // Start one task for sure; the rest incrementally
                // 将第一个任务提交, 并将结果加入到futures结果集中。其余的后续添加。
                 // 由于CPU执行效率非常高, 当添加多个任务执行时, 可能会存在并发执行多个任务的时候,             但是返回值只会是最先执行完成的任务。
                // 其他任务会调cancel方法, 取消其他任务。
                futures.add(ecs.submit(it.next()));
                // 任务数量-1
                --ntasks;
                // 当前正在执行的任务数量
                int active = 1;
    			// 循环等待是否有任务完成
                for (;;) {
                    // 从结果列表中获取头结点
                    Future<T> f = ecs.poll();
                    // 头结点对应的结果==null, 表示还没有任务完成
                    if (f == null) {
                        // 剩余的任务数量>0
                        if (ntasks > 0) {
                            // 继续执行后续任务, 并将结果添加到futures结果集中。
                            --ntasks;
                            futures.add(ecs.submit(it.next()));
                            ++active;
                        }
                        // 如果当前执行的任务数量==0, 表示有任务已经完成
                        else if (active == 0)
                            break;
                        // 是否存在超时时间
                        else if (timed) {
                            // 在超时时间范围内获取结果
                            f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                            if (f == null)
                                throw new TimeoutException();
                            // 计算剩余的超时时间
                            nanos = deadline - System.nanoTime();
                        }
                        else
                            // 所有任务都提交执行了,并且没有一个执行完,并且没有超时时间,则使用take方法一直等待
                            // 执行结果,而不是使用poll方法。
                            // poll和take方法的却别:poll方法如果队列中没有数据直接返回null,不会等待,如果有则返回
                            // 队头节点。take方法也是获取队头节点,区别在于如果队列中没有元素,则会一直等待,直到队列非空。
                            // take方法使用的是await没有超时时间所以会一直等待结果的出现。而poll方法,如果没有设置超时时间,则不会等待,
                            // 有就返回,没有就返回null,如果设置了超时时间,则使用awaitNanos方法进行等待,如果在超时时间范围内返回结果,
                            // 那么就直接返回结果,如果超过超时时间就抛出TimeoutException异常。 
                            f = ecs.take();
                    }
                    if (f != null) {
                        --active;
                        try {
                            return f.get();
                        } catch (ExecutionException eex) {
                            ee = eex;
                        } catch (RuntimeException rex) {
                            ee = new ExecutionException(rex);
                        }
                    }
                }
    
                if (ee == null)
                    ee = new ExecutionException();
                throw ee;
    
            } finally {
                for (int i = 0, size = futures.size(); i < size; i++)
                    // 实际并不能完全中断任务线程,只是通过调用线程的interrupt方法设置打断标志。让任务线程中包含sleep,wait,join等阻塞逻辑的线程抛出异常,从而中断线程执行。
                    // FutureTask cancel方法,尝试取消任务的执行。如果任务已完成或以取消返回false。
                    // 只有是new状态的任务才能取消,如果是其他状态则不能取消,返回false
                    futures.get(i).cancel(true);
            }
        }

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值