Java Future接口,用户希望执行表示异步计算结果、检查计算是否完成、在必要时取消计算、检索计算结果等操作,可以使用能实现 java.util.concurrent.Future
接口的 CompletableFuture
类。
Java Future接口 问题描述
用户希望执行表示异步计算结果、检查计算是否完成、在必要时取消计算、检索计算结果等操作。
Java Future接口 解决方案
使用能实现 java.util.concurrent.Future
接口的 CompletableFuture
类。
Java Future接口 具体实例
在本书介绍的 Java 8 和 Java 9 新特性中,CompletableFuture
是一种非常有用的类。由于 CompletableFuture
类可以实现 Future
接口,我们有必要对这种接口的用法做一简要回顾。
Java 5 引入的 java.util.concurrent
包让开发人员可以在更高的抽象层次上操作并发,而不仅限于使用简单的 wait
和 notify
原语。java.util.concurrent
包定义了一种名为 ExecutorService
的接口,其 submit
方法传入 Callable
,并返回包装所需对象的 Future
。
如例 9-15 所示,程序将任务提交给 ExecutorService
并打印字符串,然后在 Future
中检索值。
例 9-15 提交
Callable
并返回Future
ExecutorService service = Executors.newCachedThreadPool();
Future<String> future = service.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(100);
return "Hello, World!";
}
});
System.out.println("Processing...");
getIfNotCancelled(future);
例 9-16 显示了 getIfNotCancelled
方法的应用。
例 9-16 在
Future
中检索值
public void getIfNotCancelled(Future<String> future) {
try {
if (!future.isCancelled()) { ➊
System.out.println(future.get()); ➋
} else {
System.out.println("Cancelled");
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
❶ 检查 Future
的状态
❷ 通过阻塞调用以检索 Future
的值
在本例中,isCancelled
方法的用途不言自明;get
方法用于在 Future
中检索值,该方法属于阻塞调用(blocking call),返回的是其内部的泛型类型;getIfNotCancelled
方法采用 try/catch 代码块处理声明的异常。
输出结果如下:
Processing...
Hello, World!
由于所提交的调用会立即返回 Future<String>
,程序将马上打印“Processing…”。之后调用 get
代码块直到 Future
完成,并打印结果。
既然本书重点讨论 Java 8,我们不妨采用 lambda 表达式替换 Callable
接口的匿名内部类实现,如例 9-17 所示。
例 9-17 使用 lambda 表达式并检查
Future
是否完成
future = service.submit(() -> { ➊
Thread.sleep(10);
return "Hello, World!";
});
System.out.println("More processing...");
while (!future.isDone()) { ➋
System.out.println("Waiting...");
}
getIfNotCancelled(future);
❶ 使用 lambda 表达式替换 Callable
❷ 等待 Future
完成
可以看到,除使用 lambda 表达式之外,程序还在 while
循环中调用 isDone
方法以轮询 Future
,直至它完成。
在循环中使用
isDone
方法称为忙等待(busy waiting),由于该方法可能产生数百万次调用,通常属于应该避免的操作。12CompletableFuture
类(详见范例完成CompletableFuture
、范例多个CompletableFuture之间的协调一 与范例多个CompletableFuture之间的协调二可以在Future
完成时提供更好的处理方式。
12某些情况下可能需要忙等待,如广泛用于操作系统内核的自旋锁(spinlock)。不过,自旋锁的持有时间过长会阻止其他线程运行,导致系统性能降低。——译者注
例 9-17 的输出结果如下:
More processing...
Waiting...
Waiting...
Waiting...
// 一直等待
Waiting...
Waiting...
Hello, World!
当某个 Future
完成时,程序显然需要一种更有效的方式来通知开发人员,计划将这个 Future
的结果用于其他操作时更是如此。CompletableFuture
类的作用就在于此。
此外,可以通过 Future
接口定义的 cancel
方法取消操作,如例 9-18 所示。
例 9-18 取消
Future
future = service.submit(() -> {
Thread.sleep(10);
return "Hello, World!";
});
future.cancel(true);
System.out.println("Even more processing...");
getIfNotCancelled(future);
输出结果如下:
Even more processing...
Cancelled
由于 CompletableFuture
类实现了 Future
接口,本范例讨论的所有方法同样适用于 CompletableFuture
类。