# Java `Callable Future`示例

> 原文： [https://howtodoinjava.com/java/multi-threading/java-callable-future-example/](https://howtodoinjava.com/java/multi-threading/java-callable-future-example/)

[Java 执行器框架](https://howtodoinjava.com/java/multi-threading/java-thread-pool-executor-example/ "executor")的好处之一是，我们可以运行并发任务，这些并发任务在处理任务后可以返回单个结果。 [Java 并发](https://howtodoinjava.com/java-concurrency-tutorial/) API 通过以下两个接口[`Callable`](https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/Callable.html "Callable")和[`Future`](https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/Future.html "Future")实现此目的。

## 1\. Java `Callable`和`Future`接口

#### 1.1 `Callable`

`Callable`接口具有`call()`方法。 在这种方法中，我们必须实现任务的逻辑。 `Callable`接口是一个参数化接口，这意味着我们必须指出`call()`方法将返回的数据类型。

#### 2.2 `Future`

`Future`接口具有获取`Callable`对象生成的结果并管理其状态的方法。

## 2\. Java `Callable Future`示例

在此示例中，我们正在创建类型为`Callable`的`FactorialCalculator`。 这意味着我们将覆盖它的`call()`方法，计算后，我们将从`call()`方法返回结果。 以后可以从主程序保存的`Future`参考中检索此结果。

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

	private Integer number;

	public FactorialCalculator(Integer number) {
		this.number = number;
	}

	@Override
	public Integer call() throws Exception {
		int result = 1;
		if ((number == 0) || (number == 1)) {
			result = 1;
		} else {
			for (int i = 2; i <= number; i++) {
				result *= i;
				TimeUnit.MILLISECONDS.sleep(20);
			}
		}
		System.out.println("Result for number - " + number + " -> " + result);
		return result;
	}
}

```

现在，我们使用两个线程和 4 个数字测试上述阶乘计算器。

```java
package com.howtodoinjava.demo.multithreading;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CallableExample 
{
	  public static void main(String[] args) 
	  {
		  ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

		  List<Future<Integer>> resultList = new ArrayList<>();

		  Random random = new Random();

		  for (int i=0; i<4; i++)
		  {
		      Integer number = random.nextInt(10);
		      FactorialCalculator calculator  = new FactorialCalculator(number);
		      Future<Integer> result = executor.submit(calculator);
		      resultList.add(result);
		  }

		  for(Future<Integer> future : resultList)
		  {
	            try 
	            {
	                System.out.println("Future result is - " + " - " + future.get() + "; And Task done is " + future.isDone());
	            } 
	            catch (InterruptedException | ExecutionException e) 
	            {
	                e.printStackTrace();
	            }
	        }
	        //shut down the executor service now
	        executor.shutdown();
	  }
}

```

程序输出。

```java
Result for number - 4 -> 24
Result for number - 6 -> 720
Future result is -  - 720; And Task done is true
Future result is -  - 24; And Task done is true
Result for number - 2 -> 2
Result for number - 6 -> 720
Future result is -  - 720; And Task done is true
Future result is -  - 2; And Task done is true

```

在这里，我们使用`submit()`方法发送了一个`Callable`对象，该对象将在执行器中执行。 此方法接收`Callable`对象作为参数，并返回一个`Future`对象，我们可以将其用于两个主要目标：

1.  **我们可以控制任务的状态** – 我们可以取消任务并检查任务是否完成。 为此，我们使用`isDone()`方法检查任务是否完成。
2.  **我们可以通过`call()`方法返回结果**。为此，我们使用了`get()`方法。 该方法一直等到`Callable`对象完成对`call()`方法的执行并返回其结果。

    如果在`get()`方法等待结果时线程被中断，则它将引发`InterruptedException`异常。 如果`call()`方法引发异常，则此方法引发`ExecutionException`异常。

`Future`接口提供了`get()`方法的另一个版本，即`get(longtimeout, TimeUnitunit)`。 如果任务的结果不可用，则此版本的`get`方法将等待指定的时间。 如果经过指定的时间段且结果尚不可用，则该方法将返回`null`值。

学习愉快！