线程池 二、深度源码解析AbstractExecutorSerivice

版权声明:如需转载,请标明转载出处哦! https://blog.csdn.net/Z0157/article/details/81176471

AbstractExecutorService是一个抽象类,他实现了ExecutorSerivice接口,拿出上一篇的图:

对接口中的方法进行了实现!但是是抽象的类,无法实例化!

我们再看看他的子类可以实例化的一个类,ThreadPoolExecutor (extends AbstractExecutorService)他继承了AbstractExecutorService,其实 ThreadPoolExecutor才是线程池的真正实现,他通过构造方法的一系列参数,来构成不同配置的线程池;我们本章重点是看AbstractExecutorService:

其实我们看源代码会发现 AbstractExecutorService实现了ExecutorService接口,实现了submit等等方法,仍把execute方法留待子类实现。也就是说该抽象类AbstractExecutorService中并未对execute进行实现,也就是任务具体执行留给了子类;

1、提交任务(submit):

提交任务:创建任务(任务分2种),执行任务,返回任务;

在这里我先简单说明下Callable和Runnable主要区别:(后面章节具体介绍着2种方法使用)

(1)、Callable的call()方法可以有返回值,而Runnable接口run方法中没有;

(2)、Callable的call()方法可以声明抛异常,Runnable接口run中不可以声明抛异常

任务创建是有状态的,当newTaskFor的时候,任务的状态state = NEW;

执行任务:execute(task);说到执行任务,我们就会想到线程,因为任务肯定是在某个线程下才能去执行完成,而这里的这个线程就是子类中创建的线程池中的线程,有可能是线程池中已经存在的线程也可能是线程池中新创建的线程;

掉回头我们想一想,既然任务由线程去执行,那我提交任务submit这个操作是由哪个线程去执行的呢?在这里我们可以想象有一个业务主线程,他创建了线程池,然后有创建了任务,并把任务提交到了线程池;我们在看看真正执行execute(task)的方法具体实现在AbstractExecutorService子类中,所以这个submit()的方法他不是阻塞的,他是线程异步的一个实现;并且返回了任务的future;

2、invokeAny ()源码解析:

invokeAny取得第一个方法的返回值,当第一个任务结束后,会调用interrupt方法中断其它任务;

invokeAny最终是通过doInvokeAny实现的;

我们看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);
		/**
        通过构造函数,构造一个线程池服务类,其中属性中抽象了一个AbstractExecutorService服务,
		和一个阻塞的队列,这个阻塞的队列completionQueue,是线程池中已经完成的任务done会被添加
		到这个队列中;
		*/
        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.add(ecs.submit(it.next()));
            --ntasks;
            int active = 1;
			//无限循环
            for (;;) {
			//取出已经完成的任务
                Future<T> f = ecs.poll();
				//如果没有已经完成的任务
                if (f == null) {
				//并且除去已经提交的任务只玩剩余的任务数量是大于0的
                    if (ntasks > 0) {
                        --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
                        f = ecs.take();//从队列中获取已经完成的任务,并一直等待到获取不为null
                }
                if (f != null) {
                    --active;//如果不为null,即有任务完成,则激活的任务数量-1
                    try {
                        return f.get();//返回future结果
                    } 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++)
                futures.get(i).cancel(true);
        }
    }

上面字太小了,我还是复制下来吧: 

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);
        /**通过构造函数,构造一个线程池服务类,其中属性中抽象了一个AbstractExecutorService服务,
        和一个阻塞的队列,这个阻塞的队列completionQueue,是线程池中已经完成的任务done会被添加
        到这个队列中;
        */
        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.add(ecs.submit(it.next()));
            --ntasks;
            int active = 1;
            //无限循环
            for (;;) {
            //取出已经完成的任务
                Future<T> f = ecs.poll();
                //如果没有已经完成的任务
                if (f == null) {
                //并且除去已经提交的任务只玩剩余的任务数量是大于0的
                    if (ntasks > 0) {
                        --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
                        f = ecs.take();//从队列中获取已经完成的任务,并一直等待到获取不为null
                }
                if (f != null) {
                    --active;//如果不为null,即有任务完成,则激活的任务数量-1
                    try {
                        return f.get();//返回future结果
                    } 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++)
                futures.get(i).cancel(true);
        }
    }

通过源代码我们发现一个服务类:ExecutorCompletionService,他就是主角,这个服务类他实现了一个接口,

并且引用了Executor接口和AbstractExecutorSerivice抽象类服务;具体源码的内部逻辑分析我见上面的代码中汉语解释;

看了汉语注释是不是立刻就懂了该方法的原理实现了!哈哈

3、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) {
                RunnableFuture<T> f = newTaskFor(t);
                futures.add(f);
                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);
        }
    }

这个方法源码我就不解释了,很简单,只是他是要求全部完成任务,自己去理解源码吧!太晚了我得睡觉了。。。。

猜你喜欢

转载自blog.csdn.net/Z0157/article/details/81176471