一、Future模式
1.Future简介
Future本身是一种被广泛运用的开发设计模式,在很大程度上简化需要数据流同步的并发应用开发。Future对象本身可以看做是一个显示的引用,他的核心思想是异步调用,类似于ajax的异步请求,无需等待请求的结果,可以继续去处理其他的业务。
例如就像现在在网上买东西,选中东西付款之后,不会立即拿到东西,而是拿到一个买东西的订单号,然后过一段时间之后根据订单号去拿真正的货物,而在等待货物的期间我们是可以去干别的任何事情。其中Future接口就是订货单,真正处理订单的是Executor类,他根据Future接口的要求来生产产品。
2.Future接口
下面是Future接口中的定义的方法,包括5个接口方法,这5个接口方法实际上提供了Future的3个功能:判断任务是否完成,中断任务,获取任务的执行结果。
public interface Future<V> {
/**
* 取消任务的执行
* 如果任务已经完成,或者已经被取消,或者因为其他原因不能被取消,则返回失败
* 如果任务在调用时还未启动,那么返回成功
* 如果任务已经在执行过程中,则根据参数确定此执行任务的线程能否被中断,来试图停止任务的执行
* @param mayInterruptIfRunning
* @return
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* 判断任务是否已经取消,任务正常完成前将其取消,则返回true
* @return
*/
boolean isCancelled();
/**
* 判断任务是否已经完成,需要注意的是如果任务正常、异常或取消,都返回true
* @return
*/
boolean isDone();
/**
* 等待任务执行结束,并返回结果
* @return
* @throws InterruptedException 线程被中断异常
* @throws ExecutionException 任务执行异常
*/
V get() throws InterruptedException, ExecutionException;
/**
* 等待任务执行结束,并返回结果,同上面get方法的区别是设置了超时时间,
* @param timeout
* @param unit
* @return
* @throws InterruptedException
* @throws ExecutionException
* @throws TimeoutException
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
3.Future模式执行的原理
角色 | 作用 |
---|---|
main | 启动系统的主程序,调用client发送请求 |
client | 返回Data对象,并且立即返回FutureData结果 ,同时开启ClientThread线程来装配RealData |
Data | 返回数据的接口 |
FutureData | client请求之后立即返回的一个“虚假”的结果 |
RealData | 真实的结果数据 |
二、FutureTask实现
1.FutureTask介绍
Future只是一个接口,无法直接创建对象,因此有了FutureTask。RunnableFuture继承了Runnable和Future接口,而FutureTask实现了RunnableFuture接口。
public class FutureTask<V> implements RunnableFuture<V> {
……
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
2.FutureTask中的变量
/**
* state状态变化的方式
* 1.正常完成的流程:NEW -> COMPLETING -> NORMAL
* 2.出现异常的流程:NEW -> COMPLETING -> EXCEPTIONAL
* 3.被取消:NEW -> CANCELLED
* 4.被中断:NEW -> INTERRUPTING -> INTERRUPTED
*/
//记录task的状态
private volatile int state;
//新建,也表示内部成员callable已成功赋值,一直到工作线程完成FutureTask中的run()
private static final int NEW = 0;
//执行中,工作线程在处理task时的中间状态,处于该状态是,说明工作线程正准备设置result
private static final int COMPLETING = 1;
//正常,设置result结果完成,FutureTask处于该状态,代表过程结果,该状态为正确完成的最终状态
private static final int NORMAL = 2;
//异常:task在指向过程中出现异常,也是最终态
private static final int EXCEPTIONAL = 3;
//取消:task被取消,最终态
private static final int CANCELLED = 4;
//中断中:task运行过程中被中断时,设置的中间状态
private static final int INTERRUPTING = 5;
//被中断:中断完成的最终状态
private static final int INTERRUPTED = 6;
//具体run()运行时会调用其方法call(),并获取结果,结束执行置为null
private Callable<V> callable;
//伴随state进行读写
private Object outcome;
//具体的工作线程
private volatile Thread runner;
//并发stack数据结构,用于存放阻塞在该FutureTask.get方法的线程 Treiber算法参考Lock-Free算法
private volatile WaitNode waiters;
2.FutureTask的run()方法
下面是FutureTask的run()方法的执行过程,主要分为几个步骤:
(1)判断当前任务的状态,如果任务的状态不是new,说明状态已经发生了变化,执行的路径是上面4种中的一种,直接返回。
(2)如果工作线程是null,则把当前执行任务的线程赋值给runner,如果runner不为null,说明已经有线程在执行,直接返回。此处使用compareAndSwapObject来对工作线程进行赋值,是因为该方法能够保证原子性,保证多个线程同时提交一个FutureTask时,确保该FutureTask的run只被调用一次,如果想运行多次,使用runAndReset()方法。
(3)开始执行任务,如果执行的任务不为空,并且任务的状态是new,调用Callable的call方法。
(4)如果任务执行成功则set结果,如果出现异常则setException
(5)把runner设置为null
public void run() {
//首先判断任务的状态,如果任务不是new状态,说明任务的状态已经开始改变,4中可能中的一种
if (state != NEW ||!UNSAFE.co