多线程之FutureTask与Exception

在线程池中,如果一个线程抛出一个线程,只有调用future.get方法的时候,我们才知道,否则就什么都不知道了。
如果一个线程抛异常了,为什么我们调用get的时候可以知道呢?这是future将子线程内部的异常给封装起来了。
我们来看代码ThreadPoolExecutor的submit方法(实现在父类AbstractExecutorService中):

    public  Future submit(Callable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

可以看到这个类返回了一个RunnableFuture,不过RunnableFuture是一个接口,这里的实现类我们要看代码 newTaskFor()这个方法:

protected  RunnableFuture newTaskFor(Callable callable) {
        return new FutureTask(callable);
}

这里我们可以看到new了一个FutureTask,那么我们可以看一下FutureTask这个类,这个类从名字上看,是一个Future, 也是一个Task, 是Future,则有get方法和其他的一些方法, 是Task这有run方法。
我们先看get方法吧:

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

从上面的代码中可以看到,如果任务没有执行完成,则需要等待,如果执行完成了,则就调用report方法

    private V report(int s) throws ExecutionException {
        Object x = outcome;
        if (s == NORMAL)
            return (V)x;
        if (s >= CANCELLED)
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }

我们看到,这里最后会抛出ExecutionException,这个异常将x包装了一下。这里看到x即可以是一个正常的返回值,也可以是一个异常。
那我们需要看一下这个x赋值的地方,简单猜想一下,这个异常应该是在run方法中的catch部分中获得的,下面我们看run方法源码。

public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

这里我们很容易找到catch部分,setExeception:

    protected void setException(Throwable t) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = t;
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
            finishCompletion();
        }
    }

看到这里,我们就知道了,出异常是将throwable 给到outcome,get的时候,就将outcome封装成ExecutionException并抛出。

你可能感兴趣的:(多线程之FutureTask与Exception)