奇怪的异常传播到主线程

时间:2017-02-27 14:38:09

标签: java multithreading exception-handling future runnable

在下面的例子中,为什么两个异常都会传播到主线程?

(这是我配置为在调用stop()时抛出运行时异常的测试):

    List<Future> futures = new ArrayList<>();
    futures.add(executorService.submit(runnable1));
    futures.add(executorService.submit(runnable2));
    Thread.sleep(1000L); // wait for runnables to run for a while
    runnable2.stop();
    runnable1.stop();

    for (Future future : futures) {
        try {
            future.get();
        } catch(Exception e) {
            System.out.println("Exception occurred");
        }
    }

我希望只有第一个被传播,因为第二个被吞下这个设置(因为它通过循环遍历数组列表顺序等待第一个runnable)。

如果我们只调用runnable2.stop(),就可以看到这种吞咽的一个例子 - 在这种情况下根本没有显示任何内容。

为什么会打印runnable2的例外?

我还应该提一下,当在每个线程上调用stop()时,在抛出异常以允许仍然调用期货循环之前,方法内部会有一个暂停。

2 个答案:

答案 0 :(得分:1)

如果你只在第二个上调用stop(),那么for循环将永远等待第一个完成。这个例外没有被吞下;如果您的程序在第二个未来调用get(),但是您的程序已经等待第一个未来,并且无法达到该点,那么它已被捕获并将被抛出。

答案 1 :(得分:0)

  

在下面的例子中,为什么两个异常都会传播到主线程?

这是Future类的性质。它包装了你的工作,所以无论正在执行和完成的工作的顺序如何,它都会返回结果或在你致电future.get()时抛出异常。

因此,如果第二个作业首先抛出异常,它将存储在与作业关联的Future中,以便稍后通过futures列表时可以返回,即使是第一个future.get()可能需要等待第一份工作完成。

如果您愿意,可以查看FutureTask的代码。以下是一些片段:

public void run() {
  ...
            try {
                // Gray: this calls your job, storing the result
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                // this puts ex into result and sets the state to EXCEPTIONAL
                setException(ex);
            }

然后:

public V get() throws InterruptedException, ExecutionException {
   ...

    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);

因此,当运行结束时,call()方法的结果或结果异常与outcome一起存储在state中,NORMAL或{EXCEPTIONAL 1}}。