原文: https://howtodoinjava.com/java/multi-threading/java-callable-future-example/

Java 执行器框架的好处之一是,我们可以运行并发任务,这些并发任务在处理任务后可以返回单个结果。 Java 并发 API 通过以下两个接口CallableFuture实现此目的。

1. Java CallableFuture接口

1.1 Callable

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

2.2 Future

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

2. Java Callable Future示例

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

  1. public class FactorialCalculator implements Callable<Integer>
  2. {
  3. private Integer number;
  4. public FactorialCalculator(Integer number) {
  5. this.number = number;
  6. }
  7. @Override
  8. public Integer call() throws Exception {
  9. int result = 1;
  10. if ((number == 0) || (number == 1)) {
  11. result = 1;
  12. } else {
  13. for (int i = 2; i <= number; i++) {
  14. result *= i;
  15. TimeUnit.MILLISECONDS.sleep(20);
  16. }
  17. }
  18. System.out.println("Result for number - " + number + " -> " + result);
  19. return result;
  20. }
  21. }

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

  1. package com.howtodoinjava.demo.multithreading;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.Random;
  5. import java.util.concurrent.Callable;
  6. import java.util.concurrent.ExecutionException;
  7. import java.util.concurrent.Executors;
  8. import java.util.concurrent.Future;
  9. import java.util.concurrent.ThreadPoolExecutor;
  10. import java.util.concurrent.TimeUnit;
  11. public class CallableExample
  12. {
  13. public static void main(String[] args)
  14. {
  15. ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
  16. List<Future<Integer>> resultList = new ArrayList<>();
  17. Random random = new Random();
  18. for (int i=0; i<4; i++)
  19. {
  20. Integer number = random.nextInt(10);
  21. FactorialCalculator calculator = new FactorialCalculator(number);
  22. Future<Integer> result = executor.submit(calculator);
  23. resultList.add(result);
  24. }
  25. for(Future<Integer> future : resultList)
  26. {
  27. try
  28. {
  29. System.out.println("Future result is - " + " - " + future.get() + "; And Task done is " + future.isDone());
  30. }
  31. catch (InterruptedException | ExecutionException e)
  32. {
  33. e.printStackTrace();
  34. }
  35. }
  36. //shut down the executor service now
  37. executor.shutdown();
  38. }
  39. }

程序输出。

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值。

学习愉快!