【并发编程】- ExecutorService的方法invokeAny与执行快的任务异常处理(2)

47 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情

方法invokeAny()与执行快的任务异常

先出现异常而不影响后面任务的取值的原理是在代码中一直判断有没有正确的返回值,如果知道最后都没有获取返回值则抛出异常,这个异常是最后出现的异常,

例如a、b、c 这三个任务一起被执行,都出现了异常,那么最终的异常就是在最后出现的异常,可以查看AbstractExecutorService类的方法中的源码。 private T doInvokeAny(Collection<? extends Callable> tasks, boolean timed, long nanos)

第一个线程执行代码如下:

public class FCallable implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println(super.getClass().getName()+"  开始时间:  "+System.currentTimeMillis());
        for (int i = 0; i < 6789 ; i++) {
            Math.random();
            Math.random();
            Math.random();
        }
        System.out.println(super.getClass().getName()+"  结束时间:  "+System.currentTimeMillis());
        return super.getClass().getName();
    }
}

第二个线程执行代码如下:

public class SCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        try{
            System.out.println(super.getClass().getName()+" 开始时间: "+System.currentTimeMillis());
            for (int i = 0; i < 2345 ; i++) {
                Math.random();
                Math.random();
                Math.random();
            }
            if(true){
                System.out.println(super.getClass().getName()+"线程中断了....");
                throw new NullPointerException();
            }
            System.out.println(super.getClass().getName()+" 结束时间: "+System.currentTimeMillis());
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("通过显式try-catch捕获异常了,异常原因:"+e.getMessage());
            throw e;
        }
        return super.getClass().getName();
    }
}

运行类执行代码如下:

public class InvokeAnyRun {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new SCallable());
        list.add(new FCallable());
        ExecutorService executorService = Executors.newCachedThreadPool();
        try {
            String result = (String) executorService.invokeAny(list);
            System.out.println("已完成任务的返回值:"+result);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("InterruptedException");
        } catch (ExecutionException e) {
            e.printStackTrace();
            System.out.println("ExecutionException");
        }
    }
}

运行结果如下:

com.ozx.concurrentprogram.executor.service.FCallable 开始时间: 1661241426469

com.ozx.concurrentprogram.executor.service.SCallable 开始时间: 1661241426469

com.ozx.concurrentprogram.executor.service.SCallable线程中断了....

通过显式try-catch捕获异常了,异常原因:null

com.ozx.concurrentprogram.executor.service.FCallable 结束时间: 1661241426475

已完成任务的返回值:com.ozx.concurrentprogram.executor.service.FCallable java.lang.NullPointerException at com.ozx.concurrentprogram.executor.service.SCallable.call(SCallable.java:22) at com.ozx.concurrentprogram.executor.service.SCallable.call(SCallable.java:10) at java.util.concurrent.FutureTask.runcapture(FutureTask.java:266) at java.util.concurrent.FutureTask.run(FutureTask.java) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runcapture(FutureTask.java:266) at java.util.concurrent.FutureTask.run(FutureTask.java) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)

从运行结果看出第二个线程发生异常,线程中断了,但是没有在控制台输出空指针异常相关的信息,所以最后对第一个线程的结果值进行输出,因为第一个线程没出现异常。