Future和FutureTask实现异步计算

简介:

开发Android APP经常会使用AsyncTask框架来异步加载资源或者异步到服务器拉消息,等任务完成后再主动更新结果到UI主线程,AsyncTask框架可以非常方便的获取线程异步执行结果。Java 5之前,Java 并没有提供API用于查询线程是否执行完毕以及如何获取线程执行的结果;Java 5 之后版本提供的并发框架包java.util.concurrent对多线程提供了更多更好的支持,Future接口和FutureTask类是异步执行任务的框架的重要组成部分,为了更清楚的理解,我们还得从Runnable、Callable、ExecutorService等接口说起。


Runnable接口:instance可以使用new Thread(Runnable r)放到一个新线程中跑,没有返回结果;也可以使用ExecutorService.submit(Runnable r)放到线程池中跑,返回结果为null,等于没有返回结果,但可以通过返回的Future对象查询执行状态。

1
public  abstract  void  run();


Callable接口:instance只能在ExecutorService的线程池中跑,但有返回结果,也可以通过返回的Future对象查询执行状态。表面上可以把Callable接口简单的理解为有返回结果的Runnalbe接口。

1
V call()  throws  Exception;


ExecutorService接口:线程池执行调度框架

1
2
3
4
5
<T> Future<T> submit(Callable<T> task);
 
<T> Future<T> submit(Runnable task, T result);
 
Future<?> submit(Runnable task);


Future接口:用于查询任务执行状态,获取执行结果,或者取消未执行的任务。在ExecutorService框架中,由于使用线程池,所以Runnable与Callable实例都当做任务看待,而不会当做“线程”看待,所以Future才有取消任务执行等接口。接口中的get()方法用于获取任务执行结果,因为任务是异步执行的,所以我们可以在需要使用结果的时候才调用get()方法,调用时如果任务还未执行完就会阻塞直到任务完成;当然我们也可以调用get的另一重载版本get(long timeout, TimeUnit unit),当阻塞时会等待指定的时间,如果时间到而任务还未完成,那么就会抛出TimeoutException。

1
2
3
4
5
6
7
8
9
10
     boolean  cancel( boolean  mayInterruptIfRunning);
 
     boolean  isCancelled();
 
     boolean  isDone();
 
     V get()  throws  InterruptedException, ExecutionException;
 
     V get( long  timeout, TimeUnit unit)
         throws  InterruptedException, ExecutionException, TimeoutException;


FutureTask类:集Runnable、Callable、Future于一身,它首先实现了Runnable与Future接口,然后在构造函数中还要注入Callable对象(或者变形的Callable对象:Runnable + Result),所以FutureTask类既可以使用new Thread(Runnable r)放到一个新线程中跑,也可以使用ExecutorService.submit(Runnable r)放到线程池中跑,而且两种方式都可以获取返回结果,但实质是一样的,即如果要有返回结果那么构造函数一定要注入一个Callable对象,或者注入一个Runnable对象加一个预先给定的结果(个人觉得这作用不大)。

1
2
3
4
5
6
7
8
public  interface  RunnableFuture<V>  extends  Runnable, Future<V>{
...}
 
public  class  FutureTask<V>  implements  RunnableFuture<V> {
public  FutureTask(Callable<V> callable)
public  FutureTask(Runnable runnable, V result)
...
}


示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package  com.stevex.app.forkjoin;
 
import  java.util.Random;
import  java.util.concurrent.Callable;
import  java.util.concurrent.ExecutionException;
import  java.util.concurrent.ExecutorService;
import  java.util.concurrent.Executors;
import  java.util.concurrent.FutureTask;
import  java.util.concurrent.TimeUnit;
 
public  class  FutureTaskTest {
 
     public  static  void  main(String[] args) {
         Callable<String> c =  new  Callable<String>() {
             public  String call() {
                 try  {
                     TimeUnit.SECONDS.sleep( new  Random().nextInt( 5 ));
                 catch  (InterruptedException e) {
                     e.printStackTrace();
                 }
 
                 return  "Callable--" +Thread.currentThread().getName();
             }
         };
 
         //seed a single thread
         FutureTask<String> ft1 =  new  FutureTask<String>(c);
         Thread t =  new  Thread(ft1);
         t.start();
 
         Runnable r =  new  Runnable() {
             public  void  run() {
                 try  {
                     TimeUnit.SECONDS.sleep( new  Random().nextInt( 5 ));
                 catch  (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         };
 
         FutureTask<String> ft2 =  new  FutureTask<String>(r,  "Runnable" ); //give return value directly
         FutureTask<String> ft3 =  new  FutureTask<String>(c);
         FutureTask<String> ft4 =  new  FutureTask<String>(c);
         FutureTask<String> ft5 =  new  FutureTask<String>(c);
         FutureTask<String> ft6 =  new  FutureTask<String>(c);
         
         ExecutorService es = Executors.newFixedThreadPool( 2 ); //init ExecutorService
         es.submit(ft2);
         es.submit(ft3);
         es.submit(ft4);
         es.submit(ft5);
         es.submit(ft6);
         
         
         
         try  {
             TimeUnit.SECONDS.sleep( 1 );
             
             if (ft1.isDone()){              
                 ft4.cancel( false );
                 
                 if (ft4.isCancelled()){
                     System.out.println( "task4 cancelled." );
                 }
             }
             
             if (ft2.isDone()){              
                 ft5.cancel( false );
                 
                 if (ft5.isCancelled()){
                     System.out.println( "task5 cancelled." );
                 }
             }
             
             if (ft3.isDone()){              
                 ft6.cancel( false );
                 
                 if (ft6.isCancelled()){
                     System.out.println( "task5 cancelled." );
                 }
             }
                             
             System.out.println( "task1 retult:"  + ft1.get());
             System.out.println( "task2 retult:"  + ft2.get());
             System.out.println( "task3 retult:"  + ft3.get());
             
             if (! ft4.isCancelled()){
                 System.out.println( "task4 retult:"  + ft4.get());
             }
             
             if (! ft5.isCancelled()){
                 System.out.println( "task5 retult:"  + ft5.get());
             }
             
             if (! ft6.isCancelled()){
                 System.out.println( "task6 retult:"  + ft6.get());
             }  
             
             es.shutdown(); //shut down ExecutorService
         catch  (InterruptedException e) {
             e.printStackTrace();
         catch  (ExecutionException e) {
             e.printStackTrace();
         }
 
     }
}




     本文转自sarchitect 51CTO博客,原文链接:http://blog.51cto.com/stevex/1576546 ,如需转载请自行联系原作者


相关文章
|
1月前
|
Java
异步技巧之CompletableFuture
异步技巧之CompletableFuture
43 2
|
1月前
|
Java
Java并发编程:理解并使用Future和Callable接口
【2月更文挑战第25天】 在Java中,多线程编程是一个重要的概念,它允许我们同时执行多个任务。然而,有时候我们需要等待一个或多个线程完成,然后才能继续执行其他任务。这就需要使用到Future和Callable接口。本文将深入探讨这两个接口的用法,以及它们如何帮助我们更好地管理多线程。
|
3月前
|
Java
Future:异步任务结果获取
Future:异步任务结果获取
39 0
|
5月前
|
Java
ExecutorService、Callable、Future实现有返回结果的多线程原理解析
ExecutorService、Callable、Future实现有返回结果的多线程原理解析
30 0
|
6月前
|
Java
异步编程 - 04 基于JDK中的Future实现异步编程(上)_Future & FutureTask 源码解析
异步编程 - 04 基于JDK中的Future实现异步编程(上)_Future & FutureTask 源码解析
54 0
|
7月前
|
消息中间件 Java UED
Java并发编程异步操作Future和FutureTask
生活是一个洗礼自己的过程,这个洗礼并不是传统意义上的洗礼,传统意义上的洗礼通常认为这个人的思想得到洗礼,灵魂得到洗礼,十分的清新脱俗,不世故,不圆滑,而现实的洗礼实则是让一个人褪去幼稚,褪去无知,让你变得点头哈腰,圆滑世故,我们都是动物,需要物质满足,更需要欲望填补,所以,变成自己小时候唾骂的对象也是可以理解,不过这是一个选择,你可以进行选择,只是在物欲横流的时代,多数人没有这种选择的权力!
57 0
|
8月前
|
Java
【并发技术11】Callable与Future的应用
【并发技术11】Callable与Future的应用
|
Java
Callable、Future、FutureTask在多线程中的应用场景
Callable、Future、FutureTask在多线程中的应用场景
204 0
|
Java
Future和Callable学习
通常使用线程池+Runnable的时候,会发现Runnable不能返回值,也就执行的结果情况,同时对于出现异常,我们获取异常信息,进行相应的处理。如果需要返回结果,同时需要进一步加工的时候,就可以考虑使用Future+Callable了。同时接口Future的默认实现是FutureTask,因此对于其实现get()方法,会有一个问题,就是如果前面的任务一旦执行的时间耗时较长的时候,就会出现一直阻塞的状态,此时就会出现排队等待的状态,大大影响其性能。适用场景:当一个线程需要等待另一个线程把某个任务执行完成后它才能继续执行,此时可以使用FutureTask。因为FutureTask基于AQS实现,
73 0
Future和Callable学习
|
Java
Java多线程 Future和FutureTask的区别
Java多线程 Future和FutureTask的区别
154 0
Java多线程 Future和FutureTask的区别