Future

FutureTask

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果.

 

 

Callable()

1 public interface Callable<V> {
2     V call() throws Exception;
3 }
1  public class FutureTask<V> implements RunnableFuture<V> {     
2 
3   void run();
4 
5 }

Future 实际是Runnable的子类

 

Runnable 和 Callable 的区别

Runnable 的run 方法是被线程调用的,在run 方法是异步执行的

callable 的call 方法,不是异步执行的,是由Future的run调用的

 

 

FutureTask

1     public FutureTask(Callable<V> callable) {
2         if (callable == null)
3             throw new NullPointerException();
4         this.callable = callable;
5         this.state = NEW;       // ensure visibility of callable
6     }

里面维护了Callable,状态指定为new

1     public FutureTask(Runnable runnable, V result) {
2         this.callable = Executors.callable(runnable, result);
3         this.state = NEW;       // ensure visibility of callable
4     }

 

当我们把FutureTask看作一个Future,那么它的作用就是控制Callable的call方法的执行过程,在执行的过程中自然会有状态的转换


private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;

  可能的状态转移:
(执行过程顺利完成)NEW -> COMPLETING -> NORMAL
(执行过程出现异常)NEW -> COMPLETING -> EXCEPTIONAL
(执行过程被取消)NEW -> CANCELLED
(执行过程中,线程中断)NEW -> INTERRUPTING -> INTERRUPTED

 

 

把FutureTask提交到线程池或者线程执行start时候会调用run方法,源码如下

run()方法

 1 public void run() {
 2 
 3     //如果当前不是new状态,或者当前cas设置当前线程失败则返回,只有一个线程可以成功。
 4     if (state != NEW ||
 5         !UNSAFE.compareAndSwapObject(this, runnerOffset,
 6                                      null, Thread.currentThread()))
 7         return;
 8     try {
 9         //当前状态为new 则调用任务的call方法执行任务
10         Callable<V> c = callable;
11         if (c != null && state == NEW) {
12             V result;
13             boolean ran;
14             try {
15                 result = c.call();
16                 ran = true;
17             } catch (Throwable ex) {
18                 result = null;
19                 ran = false;
20                 setException(ex);完成NEW -> COMPLETING -> EXCEPTIONAL 状态转移
21             }
22 
23             //执行任务成功则保存结果更新状态,unpark所有等待线程。
24             if (ran)
25                 set(result);
26         }
27     } finally {
28         // runner must be non-null until state is settled to
29         // prevent concurrent calls to run()
30         runner = null;
31         // state must be re-read after nulling runner to prevent
32         // leaked interrupts
33         int s = state;
34         if (s >= INTERRUPTING)
35             handlePossibleCancellationInterrupt(s);
36     }
37 }
38 
39 

set()

 1  protected void set(V v) {
 2      //状态从new->COMPLETING
 3    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
 4         outcome = v;
 5         //状态从COMPLETING-》NORMAL
 6         UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
 7         //unpark所有等待线程。
 8         finishCompletion();
 9     }
10  }


Future()的返回,get()方法
 1 public V get() throws InterruptedException, ExecutionException {
 2         int s = state;
 3         //当状态值<=COMPLETING时候需要等待,否者调用report返回
 4         if (s <= COMPLETING)
 5             s = awaitDone(false, 0L);
 6         return report(s);
 7     }
 8 

 

awaitOne();

 9     private int awaitDone(boolean timed, long nanos)
10             throws InterruptedException {
11         final long deadline = timed ? System.nanoTime() + nanos : 0L;
12         WaitNode q = null;
13         boolean queued = false;
14         for (;;) {
15 
16             //如果被中断,则抛异常
17             if (Thread.interrupted()) {
18                 removeWaiter(q);
19                 throw new InterruptedException();
20             }
21 
22             //组建单列表
23             int s = state;
24             if (s > COMPLETING) {
25                 if (q != null)
26                     q.thread = null;
27                 return s;
28             }
29             else if (s == COMPLETING) // cannot time out yet
30                 Thread.yield();
31             else if (q == null)//成立
32                 q = new WaitNode();
33             else if (!queued)
34                 queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
35                         q.next = waiters, q);
36             else if (timed) {
37 
38 
39                 nanos = deadline - System.nanoTime();
40                 //超时则返回
41                 if (nanos <= 0L) {
42                     removeWaiter(q);
43                     return state;
44                 }
45                 //否者设置park超时时间
46                 LockSupport.parkNanos(this, nanos);
47             }
48             else
49                 //直接挂起当前线程
50                 LockSupport.park(this);
51         }
52     }

1、计算deadline,也就是到某个时间点后如果还没有返回结果,那么就超时了。
2、进入自旋,也就是死循环。
3、首先判断是否响应线程中断。对于线程中断的响应往往会放在线程进入阻塞之前,这里也印证了这一点。
4、判断state值,如果>COMPLETING表明任务已经取消或者已经执行完毕,就可以直接返回了。
5、如果任务还在执行,则为当前线程初始化一个等待节点WaitNode,入等待队列。这里和AQS的等待队列类似,只不过、Node只关联线程,而没有状态。AQS里面的等待节点是有状态的。
7、计算nanos,判断是否已经超时。如果已经超时,则移除所有等待节点,直接返回state。超时的话,state的值仍然还是COMPLETING。
8、如果还未超时,就通过LockSupprot类提供的方法在指定时间内挂起当前线程,等待任务线程唤醒或者超时唤醒。

 

get方法最后调用了report方法:

53     
54     private V report(int s) throws ExecutionException {
55         Object x = outcome;
56         //状态值为NORMAL正常返回
57         if (s == NORMAL)
58             return (V)x;
59         //状态值大于等于CANCELLED则抛异常
60         if (s >= CANCELLED)
61             throw new CancellationException();
62         throw new ExecutionException((Throwable)x);
63     }

 

举例:

提前完成任务之Future task

public class Demo {

    public static void main(String[] args) throws Exception {
    Callable<Integer> call = new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            Thread.sleep(1000);
            return 1;
        }
    };
        FutureTask<Integer> task = new FutureTask<>(call);

        Thread thread = new Thread(task);

        thread.start();

        //do else

        System.out.println("干点别的");

        Integer result = task.get();

        System.out.println("拿到的结果为:"+result);
    }

}

Console:

干点别的
拿到的结果为:1

 

 

举例2:上班订蛋糕,下班取蛋糕

 

productFactory :生产产品,返回订单

 1 public class ProductFactory {
 2 
 3     public Future createProduct(String name){
 4         
 5 
 6         Future f = new Future();
 7         System.out.println("下单成功了,可以去上班了...");
 8         new Thread(new Runnable() {
 9             @Override
10             public void run() {
11                 Product p = new Product(new Random().nextInt(),name);
12                 f.setProduct(p);
13             }
14         }).start();
15         return f;
16     }
17 
18 }

Product

 1 public class Product {
 2 
 3     private int id;
 4     private String name;
 5 
 6     public int getId() {
 7         return id;
 8     }
 9 
10     public String getName() {
11         return name;
12     }
13 
14     public void setId(int id) {
15         this.id = id;
16     }
17 
18     public void setName(String name) {
19         this.name = name;
20     }
21 
22     @Override
23     public String toString() {
24         return "Product{" + "id=" + id + ", name='" + name + '\'' + '}';
25     }
26 
27     public Product(int id, String name) {
28         System.out.println("开始生产..."+name);
29         new Thread(new Runnable() {
30             @Override
31             public void run() {
32                 try {
33                     Thread.sleep(4000);
34                 } catch (InterruptedException e) {
35                     e.printStackTrace();
36                 }
37 
38             }
39         }).start();
40         
41         this.id = id;
42         this.name = name;
43         System.out.println(name+"生产完毕");
44     }
45 }

Future()

 1 public class Future {
 2 
 3     private  Product product;
 4 
 5     private boolean down;//蛋糕是否完成了
 6 
 7     public synchronized void setProduct(Product product) {
 8         if (down){
 9             return;
10         }
11 
12         this.product = product;
13         this.down = true;
14         notifyAll();
15     }
16 
17     public  synchronized Product getProduct() {
18         while (!down){
19             try {
20                 wait();
21             } catch (InterruptedException e) {
22                 e.printStackTrace();
23             }
24         }
25         return product;
26     }
27 
28 }

 

Main()

 1 public class Demo {
 2 
 3 
 4     public static void main(String[] args) {
 5         ProductFactory pf = new ProductFactory();
 6         Future f = pf.createProduct("蛋糕");
 7 
 8         System.out.println("去上班,下班取蛋糕");
 9         System.out.println("拿着蛋糕回家"+f.getProduct());
10 
11     }
12 }

 

Console:

下单成功了,可以去上班了...
去上班,下班取蛋糕
开始生产...蛋糕
蛋糕生产完毕
拿着蛋糕回家Product{id=-742988975, name='蛋糕'}

 

 

 

 

 

 

 

 

 


 

posted @ 2019-07-17 13:58  曲阳阳  阅读(542)  评论(0编辑  收藏  举报