Future
接口允许表示已经完成的任务、正在执行过程中的任务或者尚未开始执行的任务。通过 Future
接口,可以尝试取消尚未完成的任务,查询任务已经完成还是取消了,以及提取(或等待)任务的结果值。
FutureTask
类实现了 Future
,并包含一些构造函数,允许将 Runnable
或 Callable
(会产生结果的 Runnable
)和 Future
接口封装。因为 FutureTask
也实现 Runnable
,所以可以只将 FutureTask
提供给 Executor
。一些提交方法(如 ExecutorService.submit()
)除了提交任务之外,还将返回 Future
接口。
Future.get()
方法检索任务计算的结果(或如果任务完成,但有异常,则抛出 ExecutionException
)。如果任务尚未完成,那么Future.get()
将被阻塞,直到任务完成;如果任务已经完成,那么它将立即返回结果。
该示例代码与 java.util.concurrent
中的多个类关联,突出显示了 Future
的功能。它实现缓存,使用 Future
描述缓存值,该值可能已经计算,或者可能在其他线程中“正在构造”。
它利用 ConcurrentHashMap
中的原子 putIfAbsent()
方法,确保仅有一个线程试图计算给定关键字的值。如果其他线程随后请求同一关键字的值,它仅能等待(通过 Future.get()
的帮助)第一个线程完成。因此两个线程不会计算相同的值。
public class Cache<K, V> {
ConcurrentMap<K, FutureTask<V>> map = new ConcurrentHashMap();
Executor executor = Executors.newFixedThreadPool(8);
public V get(final K key) {
FutureTask<V> f = map.get(key);
if (f == null) {
Callable<V> c = new Callable<V>() {
public V call() {
// return value associated with key
}
};
f = new FutureTask<V>(c);
FutureTask old = map.putIfAbsent(key, f);
if (old == null)
executor.execute(f);
else
f = old;
}
return f.get();
}
}