共同学习Java源代码-多线程与并发-AbstractExecutorService类(二)

来源:互联网 发布:凯佰赫战盾数据 编辑:程序博客网 时间:2024/06/09 22:46
    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<T> ecs =
            new ExecutorCompletionService<T>(this);




        try {
            ExecutionException ee = null;
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            Iterator<? extends Callable<T>> it = tasks.iterator();


            futures.add(ecs.submit(it.next()));
            --ntasks;
            int active = 1;




            for (;;) {
                Future<T> f = ecs.poll();
                if (f == null) {
                    if (ntasks > 0) {
                        --ntasks;
                        futures.add(ecs.submit(it.next()));
                        ++active;
                    }
                    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();
                }
                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++)
                futures.get(i).cancel(true);
        }
    }


这个方法是执行任意一个任务的方法


判断参数任务集合是否为空 且长度是否为0 如果为空或长度为0 就抛出异常 


创建一个ArrayList对象futures 泛型为Future 将任务数放入


创建一个ExecutorCompletionService对象ecs 将本对象放入 


进入try块 


创建ExecutionException异常对象 初始值为空


然后确定任务截止时间 如果参数timed为true 截止时间就是当前时间加上第三个参数 如果timed为false 截止时间就是0


然后获取任务集合的迭代器 


然后将第一个任务添加进futures 任务数减一 创建临时变量active为1代表活跃任务


进入无限for循环 


从ecs的阻塞队列里取出第一个Future结果 赋给临时变量f


如果f为空 那么进行如下判断:


如果任务数大于0 任务数自减一 futures里添加下一个任务 active数自增


如果active数等于0 就跳出for循环 


如果timed参数为true 也就是存在任务计时 从ecs的阻塞队列里按照截止时间取出一个Future结果  如果任务为空 抛出超时异常 并在截止时间中扣除已用掉的时间 


上述判断都不成立 就调用ecs的take方法 直接从阻塞队列里取出一个Future结果 赋给临时变量f


为什么从ecs的阻塞队列里取Future结果呢?因为之前的博客里说了 ExecutorCompletionService有个内部类QueueingFuture 这个类有个done方法 任务执行完了 将Future结果放入外部类的阻塞队列里 这个逻辑要看子类对Executor接口的execute方法是否有相关实现 当然这个方法doInvokeAny是私有的 被包裹在invokeAny方法中 以ThreadPoolExecutor为例 在addWorker方法中


if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }


这里线程启动后被添加进 ExecutorCompletionService的阻塞队列中






判断如果f不为空 


active数自减一 


返回f的get方法 在catch块中实例化ExecutionException对象 






跳出for循环后 如果ExecutionException为空 就实例化这个异常并抛出 


然后循环遍历futures 挨个cancel掉其他任务






    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));
    }


这两个方法都是调用了doInvokeAny的方法 不多说了

阅读全文
0 0
原创粉丝点击