项目问题:线程池使用FutureTask得不到抛出的错误

线程池使用FutureTask得不到抛出的错误

一、使用Thread

public static void main(String[] args) {
        Test test = new Test();
        FutureTask futureTask = new FutureTask<>(test);

        Thread thread = new Thread(futureTask);
        thread.start();
        try {
            futureTask.get();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static class Test implements Callable<String> {

        @Override
        public String call() throws Exception {
            System.out.println(100 / 0);
            return "test";
        }
    }

执行结果:

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at com.jkys.drugstore.gwrpc.ActivityInfoServiceTest.main(ActivityInfoServiceTest.java:41)
Caused by: java.lang.ArithmeticException: / by zero
	at com.jkys.drugstore.gwrpc.ActivityInfoServiceTest$Test.call(ActivityInfoServiceTest.java:66)
	at com.jkys.drugstore.gwrpc.ActivityInfoServiceTest$Test.call(ActivityInfoServiceTest.java:62)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.lang.Thread.run(Thread.java:748)

二、使用线程池

public static void main(String[] args) {
        getFuture();
    }

    public static void getFuture() {
        ExecutorService executorService = Executors.newFixedThreadPool(1);

        Future<?> future =  executorService.submit(new FutureTask<>(() -> {
            System.out.println(100 / 0);
            return "test";
        }));

        try {
            System.out.println(future.get());
        } catch (Exception e) {
            System.out.println("Error!");
        }
    }


执行结果: null,没有异常

objc[9813]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java (0x10098f4c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x1029c04e0). One of the two will be used. Which one is undefined.
null

三、解析

由上面两个例子可以看出,直接用Thread配合FutureTask是可以得到子线程中的异常的,那么为什么配合线程池却得不到呢?

3.1 线程池解析—从submit开始

//AbstractExecutorService 109行
public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

//AbstractExecutorService 86行
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }

//FutureTask 151行,也就是传进来的Runnable被包装成FutureTask
 public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }

//Executors 404行
public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }

//Executors 503行
 static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }

从上面代码部分能得到:线程池submit入参是Runnable,但是经过一系列的调用最终到了FutureTask的构造器,即把入参的Runnbale适配成一个新的FutureTask。 但是如果扔到线程池中的已经是一个FutureTask呢?其实也会被当做成Runnablue去继续被包装成FutureTask。

3.2包装的FutureTask和自己扔进去的FutureTask关系图

在这里插入图片描述

3.3调用时序图

在这里插入图片描述

由上面的关系图和时序图,就能得知为什么扔到线程池中的FutureTask在主线程get的时候得不到异常了。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值