# Java `Future`教程

原文：http://zetcode.com/java/future/

Java `Future`教程展示了如何使用`Future`在 Java 中进行异步编程。

`Future`表示异步计算的结果。 提供了一些方法来检查计算是否完成，等待其完成以及检索计算结果。 简而言之，一旦某个操作完成，就有望保留该操作的结果。 `Future`是 Java 5 中引入的。

该值是使用`get()`从将来检索的，该值将阻塞直到值准备就绪。

`FutureTask`类是实现`Runnable`的`Future`的实现，因此可以由`Executor`执行。

期货有几个缺点。 例如，它们无法手动完成，并且它们不会在完成时通知。 期货不能被链接和组合。 另外，没有异常处理。 为了解决此缺点，Java8 引入了`CompletableFuture`。

## Java `Future`示例

以下示例使用期货来计算阶乘。

`com/zetcode/FactorialCalculator.java`

```java
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`计算阶乘。

```java
public class FactorialCalculator implements Callable<BigInteger> {

```

`FactorialCalculator`实现了`Callable`。 `Callable`代表返回结果的异步任务。 在我们的例子中，结果是计算的阶乘。

```java
TimeUnit.MILLISECONDS.sleep(1500);

```

我们稍微减慢了计算速度。

`com/zetcode/JavaFutureEx.java`

```java
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();
    }
}

```

我们生成六个随机整数并计算它们的阶乘。

```java
var executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

```

执行程序服务处理异步任务的生命周期。 它的`submit()`可以接受`Runnable`和`Callable`对象。

```java
var factorialCalculator = new FactorialCalculator(number);

```

创建一个`FactorialCalculator`任务。 它将异步运行。

```java
Map<Integer, Future<BigInteger>> result = new HashMap<>();
result.put(number, executor.submit(factorialCalculator));
resultList.add(result);

```

我们将任务提交给执行者。 我们将整数值和期货放置在映射上，以便手边有值和计算出的阶乘。

```java
for (Map<Integer, Future<BigInteger>> pair : resultList) {

```

我们浏览结果列表。 请注意，期货在计算其价值之前会迅速返回。

```java
var optional = pair.keySet().stream().findFirst();

if (!optional.isPresent()) {
    return;
}

var key = optional.get();

```

我们得到了一对的钥匙。

```java
var future = pair.get(key);
var result = future.get();

```

使用钥匙，我们将拥有未来。 当我们调用`get()`时，处理被阻塞，直到检索到该值为止。

```java
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 教程](/all/#java)。