Java Future 示例

2025年3月17日 | 阅读 14 分钟

Java 中,Future 是一个属于 java.util.concurrent 接口。它用于表示异步计算的结果。该接口提供了检查计算是否完成、等待其完成以及检索计算结果的方法。一旦任务或计算完成,就无法取消该计算。

语法

Java Future 示例

Java Future 的最佳示例是 ExecutorService 接口。它会从其某些方法生成 Future (来自其某些方法) 对象,用于跟踪一个或多个异步任务的进度。

Future 接口的方法

该接口提供了以下五种方法

方法描述
cancel()它尝试取消任务的执行。
get()该方法在必要时等待计算完成,然后检索其结果。
get()在必要时,最多等待给定的时间让计算完成,然后检索其结果(如果可用)。
isCancelled()如果任务在完成之前被取消,则返回 true。
isDone()如果任务已完成,则返回 true。

Future 接口存在一些不足之处,如下所示:

  • 使用 Future,无法手动完成计算。
  • 计算完成后,它不会通知。
  • 无法创建和组合其链。

为了克服上述限制,Java 8 引入了 CompletableFuture

在异步编程中使用 Future

获取结果

正如我们上面所讨论的,Future 表示异步任务的结果。为了检索该异步任务的结果,Java Future 接口提供了以下两个 get() 方法版本,它们都返回一个对象。请注意,返回类型可能是一个泛型类型。例如:

注意:如果我们尝试在异步任务完成之前调用 get() 方法,get() 方法将阻塞直到结果准备就绪。

为了克服上述缺点,Future 接口提供了另一个 get() 方法版本,该版本接受一个 **时间**(以毫秒为单位)作为参数。它表示 Future 将等待一段时间来完成任务,之后结果将在 Future 中可用。例如:

如果在指定时间内 Future 没有获得任何结果,Future 将抛出 **TimeoutException**。

取消异步任务

我们还可以通过调用 Future 接口的 cancel() 方法随时取消异步任务。例如:

检查异步任务是否完成

该接口提供了一个 isDone() 方法来检查异步任务是否完成。例如:

检查异步任务是否已取消

Future 接口提供了一个 isCancelled() 方法来检查由 Future 表示的异步任务是否已取消。如果任务成功取消,则返回 true,否则返回 false。例如:

Java Future 示例

FutureExample.java

输出

Java Future Example

将 Future 与 ExecutorService 一起使用

文件名:FutureWithExecutorServiceExample.java

输出

Task submitted.
Task completed with result: 8

取消 Future 任务

文件名:FutureTaskCancellationExample.java

输出

Task submitted.
Running... 1
Running... 2
Running... 3
Attempting to cancel the task...
Task was successfully cancelled.

使用 Future 处理异常

文件名:FutureExceptionHandlingExample.java

输出

Task submitted.
Task failed with exception: java.lang.Exception: An error occurred during task execution.

等待多个 Future

文件名:WaitingForMultipleFuturesExample.java

输出

All tasks submitted.
Task 3 will sleep for 2 seconds.
Task 2 will sleep for 2 seconds.
Task 1 will sleep for 3 seconds.
Task 4 will sleep for 3 seconds.
Task 5 will sleep for 2 seconds.
Task completed with result: 10
Task completed with result: 20
Task completed with result: 30
Task completed with result: 40
Task completed with result: 50

链式调用 Future

文件名:ChainingFuturesExample.java

输出

Task 1: Start
Task 1: End
Task 2: Start with result from Task 1: 10
Task 2: End
Task 3: Start with result from Task 2: 20
Task 3: End
All tasks completed successfully.

处理超时

文件名:CompletableFutureTimeoutExample.java

输出

Task: Start
Task timed out, could not get result.
Task: End

等待 Future 完成

文件名:WaitForFutureExample.java

输出

Task submitted to executor.
Task completed with result: 42

处理回调中的异常

文件名:HandlingException.java

输出

Exception: java.lang.RuntimeException: Something went wrong
Default value

合并 Future

文件名:CombineFuturesExample.java

输出

Task 1: Start
Task 2: Start
Task 1: End
Task 2: End
Combining results: 10 + 20
Combined result: 30

Future 接口的局限性

Java 中的 Future 接口以其管理异步操作的能力而闻名,但也存在一些值得注意的限制,这些限制会影响我们在 Java 应用程序中处理并发的方式。

  1. 阻塞操作: Future 接口的一个显著缺点是其阻塞性。具体来说,get() 方法会暂停执行直到任务完成。这可能导致效率低下,尤其是在等待多个 Future 任务时,从而削弱了异步编程的优势。
  2. 缺乏完成回调: 与响应式编程模型不同,Future 接口缺乏对完成回调的内置支持。这种缺失需要手动检查任务完成状态,效率较低,并且不利于响应式编程范例。
  3. 对合并 Future 的支持有限: Future 不提供用于合并多个 Future 或等待一组 Future 完成的内置方法。实现此类功能需要额外的样板代码,从而降低了简洁性和可读性。
  4. 异常处理的挑战: 使用 Future.get() 处理异常会带来挑战。对于计算错误,它会抛出 ExecutionException;如果在等待期间线程被中断,则会抛出 InterruptedException。它需要复杂的异常处理逻辑来有效地管理各种错误场景。
  5. 无法修改 Future 状态: 一旦启动,Future 就不能手动完成或更改其值。这限制了动态管理异步任务的灵活性。

这些限制强调了在使用 Future 接口设计并发 Java 应用程序时需要仔细考虑,并强调了简洁性和功能性之间的权衡。