开发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();
}
}
}
|