publicinterfaceFuture<V>{/** * Attempts to cancel execution of this task. This attempt will * fail if the task has already completed, has already been cancelled, * or could not be cancelled for some other reason. If successful, * and this task has not started when {@code cancel} is called, * this task should never run. If the task has already started, * then the {@code mayInterruptIfRunning} parameter determines * whether the thread executing this task should be interrupted in * an attempt to stop the task. * * <p>After this method returns, subsequent calls to {@link #isDone} will * always return {@code true}. Subsequent calls to {@link #isCancelled} * will always return {@code true} if this method returned {@code true}. * * @param mayInterruptIfRunning {@code true} if the thread executing this * task should be interrupted; otherwise, in-progress tasks are allowed * to complete * @return {@code false} if the task could not be cancelled, * typically because it has already completed normally; * {@code true} otherwise */booleancancel(booleanmayInterruptIfRunning);/** * Returns {@code true} if this task was cancelled before it completed * normally. * * @return {@code true} if this task was cancelled before it completed */booleanisCancelled();/** * Returns {@code true} if this task completed. * * Completion may be due to normal termination, an exception, or * cancellation -- in all of these cases, this method will return * {@code true}. * * @return {@code true} if this task completed */booleanisDone();/** * Waits if necessary for the computation to complete, and then * retrieves its result. * * @return the computed result * @throws CancellationException if the computation was cancelled * @throws ExecutionException if the computation threw an * exception * @throws InterruptedException if the current thread was interrupted * while waiting */Vget()throwsInterruptedException,ExecutionException;/** * Waits if necessary for at most the given time for the computation * to complete, and then retrieves its result, if available. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument * @return the computed result * @throws CancellationException if the computation was cancelled * @throws ExecutionException if the computation threw an * exception * @throws InterruptedException if the current thread was interrupted * while waiting * @throws TimeoutException if the wait timed out */Vget(longtimeout,TimeUnitunit)throwsInterruptedException,ExecutionException,TimeoutException;}
get 方法最主要的作用就是获取任务执行的结果,该方法在执行时的行为取决于 Callable 任务的状态,可能会发生以下 5 种情况。
(1)最常见的就是**当执行 get 的时候,任务已经执行完毕了**,可以立刻返回,获取到任务执行的结果。
(2)任务还没有结果,这是有可能的,比如我们往线程池中放一个任务,线程池中可能积压了很多任务,还没轮到我去执行的时候,就去 get 了,在这种情况下,相当于任务还没开始;还有一种情况是**任务正在执行中**,但是执行过程比较长,所以我去 get 的时候,它依然在执行的过程中。无论是任务还没开始或在进行中,我们去调用 get 的时候,都会把当前的线程阻塞,直到任务完成再把结果返回回来。
(3)任务执行过程中抛出异常,一旦这样,我们再去调用 get 的时候,就会抛出 ExecutionException 异常,不管我们执行 call 方法时里面抛出的异常类型是什么,在执行 get 方法时所获得的异常都是 ExecutionException。
(4)任务被取消了,如果任务被取消,我们用 get 方法去获取结果时则会抛出 CancellationException。
(5)任务超时,我们知道 get 方法有一个重载方法,那就是带延迟参数的,调用了这个带延迟参数的 get 方法之后,如果 call 方法在规定时间内正常顺利完成了任务,那么 get 会正常返回;但是如果到达了指定时间依然没有完成任务,get 方法则会抛出 TimeoutException,代表超时了。
这里要注意,我们知道这个异常实际上是在任务刚被执行的时候就抛出了,因为我们的计算任务中是没有其他逻辑的,只有抛出异常。我们再来看,控制台是什么时候打印出异常的呢?它是在 true 打印完毕后才打印出异常信息的,也就是说,在调用 get 方法时打印出的异常。
这段代码证明了三件事情:第一件事情,即便任务抛出异常,isDone 方法依然会返回 true;第二件事情,虽然抛出的异常是 IllegalArgumentException,但是对于 get 而言,它抛出的异常依然是 ExecutionException;第三个事情,虽然在任务执行一开始时就抛出了异常,但是真正要等到我们执行 get 的时候,才看到了异常。
publicinterfaceRunnableFuture<V>extendsRunnable,Future<V>{/** * Sets this Future to the result of its computation * unless it has been cancelled. */voidrun();}