Java在最初的多线程实现程序ThreadRunnable之中,是没有返回值的。这样的接口带来了很多处理多线程程序的不便。所以后来又引入了Callable接口,以及与之对应的Future接口。这样我们的多线程程序提交到线程池执行的时候就可以返回一个Future对象。然后调用Future.get()就可以获取线程的返回值。

示例

下面的两个例子给出了。多线程获取返回值的两种实现方式。一个是Java自己提供的原生Future,另外一个是Guava提供的封装接口ListenableFuture。

Java之Future示例

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
/*
* Created by guochenglai on 2/13/17.
*/
public class FutureTest {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(3);
Future<Cinema> addressFuture = executorService.submit(new Callable<Cinema>() {
@Override
public Cinema call() throws Exception {
return Cinema;
}
});
Future<Movie> movieFuture = executorService.submit(new Callable<Movie>() {
@Override
public Movie call() throws Exception {
return Movie;
}
});
Cinema cinema = CiaddressFuture.get();
Movie movie = movieFuture.get();
}
}

Guava之ListenableFuture示例

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
/*
* Created by guochenglai on 2/23/17.
*/
public class ListenableFutureTest {
public static void main(String[] args) {
ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(3));
ListenableFuture<Cinema> cinemaListenableFuture = executorService.submit(new Callable<Cinema>() {
@Override
public Cinema call() throws Exception {
return cinema;
}
});
Futures.addCallback(cinemaListenableFuture, new FutureCallback<Cinema>() {
@Override
public void onSuccess(Cinema cinema) {
}
@Override
public void onFailure(Throwable throwable) {
}
});
ListenableFuture<Movie> movieListenableFuture = executorService.submit(new Callable<Movie>() {
@Override
public Movie call() throws Exception {
return movie;
}
});
Futures.addCallback(movieListenableFuture, new FutureCallback<Movie>() {
@Override
public void onSuccess(Movie movie) {
}
@Override
public void onFailure(Throwable throwable) {
}
});
}
}

Future与ListenableFuture对比

通过上面的对比我们可以发现,使用Java的Future对象,我们必须自己去手动检查线程的返回结果。而在ListenableFuture中我们确不必这样。我们只需要写好回调函数即可。但是这并不能说明这两种实现谁更好。他们有着不同的适用场景。比如:

使用Future的场景

  • 在一个方法中有多个外部IO,而在方法的最后需要整合这些IO的处理结果。

使用Listenable的场景

  • 在UI操作的中间步骤中,给出相应的步骤提示。

ListenableFuture对Future的扩展

JdkFutureAdapters.listenInPoolThread(future)

JdkFutureAdapters.listenInPoolThread(future)是Guava提供的一种将JDK原生Future转化为ListenableFuture的方法。
例如:

1
2
3
4
5
6
7
8
9
10
Future<Movie> movieFuture = executorService.submit(new Callable<Movie>() {
@Override
public T call() throws Exception {
return Movie;
}
});
ListenableFuture<Movie> movieListenableFuture = JdkFutureAdapters.listenInPoolThread(movieFuture);

transform

对ListenableFuture的返回值进行转化
例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Future<Movie> movieFuture = executorService.submit(new Callable<Movie>() {
@Override
public T call() throws Exception {
return Movie;
}
});
ListenableFuture<UIMovie> uiMovieListenableFuture = Futures.transform(movieFuture, new AsyncFunction<Movie, UIMovie>() {
@Override
public ListenableFuture<UIMovie> apply(Movie i) throws Exception { return UIMovie;
}
});

allAsList

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
ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(3));
ListenableFuture<Cinema> cinemaListenableFuture1 = executorService.submit(new Callable<Cinema>() {
@Override
public Cinema call() throws Exception {
return cinema;
}
});
ListenableFuture<Cinema> cinemaListenableFuture2 = executorService.submit(new Callable<Cinema>() {
@Override
public Cinema call() throws Exception {
return Cinema;
}
});
ListenableFuture<Cinema> cinemaListenableFuture = Futures.allAsList(cinemaListenableFuture1, cinemaListenableFuture2);
ListenableFuture<UICiema> uiCiemaListenableFuture = Futures.transform(cinemaListenableFuture, new AsyncFunction<Cinema, UICineam>() {
@Override
public ListenableFuture<UICineam> apply(Cinema i) throws Exception {
return null;
}
});