Future(FutureTask)

  • Future:

Future是java.util.concurrent包下的一个接口,代表着一个异步计算的结果,可以通过get()获取线程执行的返回值,cancel()取消任务执行,isCancelled()isDone()获得任务执行的情况

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
V
get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }

cancel方法:

1、如果任务还未开始,cancel返回true,且任务永远不会被执行
2、如果任务正在执行,FutureTask.cancel(true)将以中断此任务线程的方式来试图停止任务
3、如果任务结束(可能是正常完成、异常终止、被取消),返回false
4、如果cancel()操作返回true,后续调用isDone()、isCancelled()都返回true
get方法:

1.get()用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回

2.get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内还没获取到结果,会抛出TimeoutException

  • FutureTask:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    //在未被取消的情况下,将此 Future 设置为计算的结果
    void run();
}

FutureTask实现RunnableFuture接口,既可以作为Runnable被执行,也可以作为Future得到Callable的返回值

由于get方法阻塞作用的存在,在多线程的情况下,某一个任务一次只能被一个线程执行,我们就可以把这个任务定义为FutureTask类型的。

 

Future.get()如何获取线程返回值?(实际上FutrueTask实现还是基于AQS的)

首先得益于Callable.call()方法定义了返回值,提交Callable任务后,Callable会被封装成FutureTask,其既可以作为Runnable被执行,也可以作为Future获取返回值,FutureTask.run()方法会调用Callable.call()中的任务代码
在任务执行完成前,如果主线程使用Future.get(),其实是调用FutureTask.get(),其中会判断任务状态尚未结束,将主线程加入waiters等待链表,并挂起主线程
待任务执行结束后,FutureTask会唤醒所有等待获取返回值的线程,此时主线程的FutureTask.get()就会返回了

所以,主线程和运行线程是通过FutureTask作为桥梁获取线程返回值的

Future.cancel()真的能取消任务执行吗?

首先答案是“不一定”,根据JDK中的方法注释“Attempts to cancel execution of this task”,即尝试去取消执行的任务
如果任务正在执行,且调用cancel()时参数mayInterruptIfRunning传的是true,那么会对执行线程调用interrupt()方法
那么问题就变成了interrupt()方法能中断线程执行吗?
interrupt()方法不会中断正在运行的线程。这一方法实际上完成的是在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更确切的说,如果线程被Object.wait()、Thread.join()、Thread.sleep()等阻塞,那么它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。
如果线程没有被阻塞,调用interrupt()将不起作用
那么即使线程正在阻塞状态,并抛出了InterruptedException,线程能否真的取消执行还要看代码中是否捕获了InterruptedException和有没有做相应的对中断标示的判断逻辑

 

 

posted @ 2019-05-30 10:21  LeeJuly  阅读(361)  评论(0)    收藏  举报