【并发编程】- 线程池使用ExecutorCompletionService与异常处理

198 阅读2分钟

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

ExecutorCompletionService类与异常

使用CompletionService执行任务的过程中不可避免会出现各种情况的异常

线程执行代码如下:

public class ExceptionFirstCallable  implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println(super.getClass().getName()+"线程执行开始时间:"+System.currentTimeMillis());
        Thread.sleep(5000);
        System.out.println(super.getClass().getName() +"线程执行结束时间:"+System.currentTimeMillis());
        return super.getClass().getName();
    }
}
public class ExceptionSecondCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println(super.getClass().getName()+"线程执行开始时间:"+System.currentTimeMillis());
        Thread.sleep(5000);
        int i = 0;
        if(i == 0){
            throw new Exception("抛出异常!");
        }
        System.out.println(super.getClass().getName() +"线程执行结束时间:"+System.currentTimeMillis());
        return super.getClass().getName();
    }
}

运行类执行代码如下:

public class ExceptionCallableRun {
    public static void main(String[] args) {
        try {
        ExceptionFirstCallable firstCallable = new ExceptionFirstCallable();
        ExceptionSecondCallable secondCallable = new ExceptionSecondCallable();

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorCompletionService executorCompletionService = new ExecutorCompletionService(executorService);
        executorCompletionService.submit(firstCallable);
        executorCompletionService.submit(secondCallable);

        for (int i = 0; i < 2 ; i++) {
                System.out.println("休眠中没获取返回值:"+executorCompletionService.take());
        }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下:

com.ozx.concurrentprogram.executor.service.ExceptionFirstCallable线程执行开始时间:1660554419064

com.ozx.concurrentprogram.executor.service.ExceptionFirstCallable线程执行结束时间:1660554424075

休眠中没获取返回值:java.util.concurrent.FutureTask@3ecf72fd

com.ozx.concurrentprogram.executor.service.ExceptionSecondCallable线程执行开始时间:1660554424077

休眠中没获取返回值:java.util.concurrent.FutureTask@7a92922

从运行结果看出ExceptionSecondCallable执行代码有异常,但是没有调用FutureTask类的get()方法,所以不出现异常。

修改运行类执行代码如下:

public class ExceptionCallableRun {
    public static void main(String[] args) {
        ExceptionFirstCallable firstCallable = new ExceptionFirstCallable();
        ExceptionSecondCallable secondCallable = new ExceptionSecondCallable();

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorCompletionService executorCompletionService = new ExecutorCompletionService(executorService);
        executorCompletionService.submit(secondCallable);
        executorCompletionService.submit(firstCallable);


        for (int i = 0; i < 2 ; i++) {
            try {
                System.out.println("获取返回值:"+executorCompletionService.take().get());
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

运行结果如下:

com.ozx.concurrentprogram.executor.service.ExceptionSecondCallable 线程执行开始时间:1660633712554

com.ozx.concurrentprogram.executor.service.ExceptionFirstCallable 线程执行开始时间:1660633717565

java.util.concurrent.ExecutionException: java.lang.Exception: 抛出异常!

​ at java.util.concurrent.FutureTask.report(FutureTask.java:122) ​ at java.util.concurrent.FutureTask.get(FutureTask.java:192) ​ at com.ozx.concurrentprogram.executor.controller.ExceptionCallableRun.main(ExceptionCallableRun.java:29) Caused by: java.lang.Exception: 抛出异常! at com.ozx.concurrentprogram.executor.service.ExceptionSecondCallable.call(ExceptionSecondCallable.java:17) ​ at com.ozx.concurrentprogram.executor.service.ExceptionSecondCallable.call(ExceptionSecondCallable.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)

com.ozx.concurrentprogram.executor.service.ExceptionFirstCallable 线程执行结束时间:1660633722573

获取返回值:com.ozx.concurrentprogram.executor.service.ExceptionFirstCallable

看执行过程是先执行有异常的任务,没异常的任务后执行,有异常的任务发生异常时后没有输出返回值,而没异常的任务能通过get()方法获取返回值。