Java Future
最后修改于 2024 年 1 月 27 日
Java Future 教程展示了如何在 Java 中使用 Future 进行异步编程。
Future 代表异步计算的结果。它提供了检查计算是否完成、等待其完成以及检索计算结果的方法。简单来说,future 是一个承诺,它保存某个操作完成后的结果。Future 是在 Java 5 中引入的。
使用 get 从 future 中检索值,get 会阻塞直到值准备好。
FutureTask 类是 Future 的一个实现,它实现了 Runnable 接口,因此可以被 Executor 执行。
Futures 有一些缺点。例如,它们不能手动完成,并且完成时不会通知。Futures 无法链接和组合。此外,没有异常处理。为了解决这些缺点,Java 8 引入了 CompletableFuture。
Java Future 示例
以下示例使用 futures 计算阶乘。
package com.zetcode;
import java.math.BigInteger;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
public class FactorialCalculator implements Callable<BigInteger> {
private int value;
public FactorialCalculator(int value) {
this.value = value;
}
@Override
public BigInteger call() throws Exception {
var result = BigInteger.valueOf(1);
if (value == 0 || value == 1) {
result = BigInteger.valueOf(1);
} else {
for (int i = 2; i <= value; i++) {
result = result.multiply(BigInteger.valueOf(i));
}
}
TimeUnit.MILLISECONDS.sleep(500);
return result;
}
}
FactorialCalculator 使用 BigInteger 计算阶乘。
public class FactorialCalculator implements Callable<BigInteger> {
FactorialCalculator 实现了 Callable 接口。 Callable 代表一个返回结果的异步任务。 在我们的例子中,结果是计算出的阶乘。
TimeUnit.MILLISECONDS.sleep(1500);
我们稍微减慢计算速度。
package com.zetcode;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
public class JavaFutureEx {
public static void main(String[] args) throws ExecutionException, InterruptedException {
var executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
List<Map<Integer, Future<BigInteger>>> resultList = new ArrayList<>();
var random = new Random();
for (int i = 0; i < 6; i++) {
int number = random.nextInt(100) + 10;
var factorialCalculator = new FactorialCalculator(number);
Map<Integer, Future<BigInteger>> result = new HashMap<>();
result.put(number, executor.submit(factorialCalculator));
resultList.add(result);
}
for (Map<Integer, Future<BigInteger>> pair : resultList) {
var optional = pair.keySet().stream().findFirst();
if (!optional.isPresent()) {
return;
}
var key = optional.get();
System.out.printf("Value is: %d%n", key);
var future = pair.get(key);
var result = future.get();
var isDone = future.isDone();
System.out.printf("Result is %d%n", result);
System.out.printf("Task done: %b%n", isDone);
System.out.println("--------------------");
}
executor.shutdown();
}
}
我们生成六个随机整数并计算它们的阶乘。
var executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
executor 服务处理异步任务的生命周期。 它的 submit 可以接受 Runnable 以及 Callable 对象。
var factorialCalculator = new FactorialCalculator(number);
创建一个 FactorialCalculator 任务。 它将异步运行。
Map<Integer, Future<BigInteger>> result = new HashMap<>(); result.put(number, executor.submit(factorialCalculator)); resultList.add(result);
我们将任务提交给 executor。 我们将整数值和 future 放入一个 map 中,以便我们手头有该值和计算出的阶乘。
for (Map<Integer, Future<BigInteger>> pair : resultList) {
我们遍历结果列表。 请注意,futures 会在其值计算之前快速返回。
var optional = pair.keySet().stream().findFirst();
if (!optional.isPresent()) {
return;
}
var key = optional.get();
我们得到该对的键。
var future = pair.get(key); var result = future.get();
使用该键,我们得到 future。 当我们调用 get 时,处理将被阻塞,直到检索到该值。
Value is: 39 Result is 20397882081197443358640281739902897356800000000 Task done: true -------------------- Value is: 99 Result is 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000 Task done: true -------------------- Value is: 39 Result is 20397882081197443358640281739902897356800000000 Task done: true -------------------- Value is: 102 Result is 961446671503512660926865558697259548455355905059659464369444714048531715130254590603314961882364451384985595980362059157503710042865532928000000000000000000000000 Task done: true -------------------- Value is: 12 Result is 479001600 Task done: true -------------------- Value is: 49 Result is 608281864034267560872252163321295376887552831379210240000000000 Task done: true --------------------
来源
在本文中,我们使用了 Java 的 Future。
作者
列出所有Java教程。