Java中Future的作用是什么 解析异步计算结果的获取方式

Java中future的主要作用是代表异步计算的结果,允许非阻塞地获取任务结果并提高并发效率。1.get()方法可阻塞式获取结果或设置超时;2.isdone()方法用于非阻塞检查任务是否完成;3.通过第三方库如guava的listenablefuture实现回调机制处理任务完成后自动执行的操作。此外,future.cancel()可用于尝试取消任务,适用于资源释放、任务超时等场景。而futuretask作为runnable和future的结合体,既能提交执行也能获取结果,其内部状态机管理任务生命周期。异常处理可通过get()中的try-catch捕获executionexception或使用回调机制处理。相比completablefuture,future功能较为基础,后者提供链式调用、组合任务、更灵活的异常处理等功能,更适合复杂异步编程需求。

Java中Future的作用是什么 解析异步计算结果的获取方式

Java中Future的主要作用是代表异步计算的结果。它允许你在提交一个任务后,不必立即等待任务完成,而是先拿到一个Future对象,稍后再通过这个对象来获取计算结果。这在并发编程中非常有用,可以提高程序的响应速度和吞吐量。

Java中Future的作用是什么 解析异步计算结果的获取方式

Future提供了一种非阻塞的方式来获取异步任务的结果,避免了线程被长时间阻塞的情况。你可以先执行其他的任务,然后在需要结果的时候再通过Future来获取。

Java中Future的作用是什么 解析异步计算结果的获取方式

解析异步计算结果的获取方式主要有三种:get() 方法、isDone() 方法和回调机制。

立即学习Java免费学习笔记(深入)”;

Java中Future的作用是什么 解析异步计算结果的获取方式

get() 方法:阻塞式获取结果,直到任务完成或超时 Future接口最常用的方法之一就是get()。当你调用future.get()时,如果任务还没有完成,调用线程会被阻塞,直到任务完成并返回结果,或者发生异常。get()方法还可以接受一个超时参数,如果在指定的时间内任务没有完成,会抛出TimeoutException。

ExecutorService executor = Executors.newFixedThreadPool(10); Future<String> future = executor.submit(() -> {     Thread.sleep(2000); // 模拟耗时操作     return "任务完成"; });  try {     String result = future.get(3, TimeUnit.SECONDS); // 设置超时时间为3秒     System.out.println("结果: " + result); } catch (InterruptedException | ExecutionException | TimeoutException e) {     e.printStackTrace(); } finally {     executor.shutdown(); }

这个例子中,如果任务在3秒内没有完成,future.get()会抛出TimeoutException。

isDone() 方法:非阻塞式检查任务是否完成 isDone()方法允许你检查任务是否已经完成,而不会阻塞当前线程。你可以使用这个方法来定期检查任务的状态,并在任务完成后获取结果。

ExecutorService executor = Executors.newFixedThreadPool(10); Future<String> future = executor.submit(() -> {     Thread.sleep(2000); // 模拟耗时操作     return "任务完成"; });  while (!future.isDone()) {     System.out.println("任务还在执行中...");     try {         Thread.sleep(500); // 每隔500毫秒检查一次     } catch (InterruptedException e) {         e.printStackTrace();     } }  try {     String result = future.get();     System.out.println("结果: " + result); } catch (InterruptedException | ExecutionException e) {     e.printStackTrace(); } finally {     executor.shutdown(); }

回调机制:任务完成后自动执行回调函数

虽然Future本身没有直接提供回调机制,但可以通过一些库(如Guava的ListenableFuture)或者自己实现类似的功能。回调机制允许你在任务完成后自动执行一段代码,而不需要手动调用get()或者isDone()。

import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors;  ExecutorService executor = Executors.newFixedThreadPool(10); ListenableFuture<String> future = MoreExecutors.listeningDecorator(executor).submit(() -> {     Thread.sleep(2000); // 模拟耗时操作     return "任务完成"; });  Futures.addCallback(future, new FutureCallback<String>() {     @Override     public void onSuccess(String result) {         System.out.println("任务成功完成,结果: " + result);     }      @Override     public void onFailure(Throwable t) {         System.err.println("任务失败: " + t.getMessage());     } }, MoreExecutors.directExecutor());  executor.shutdown();

Guava的ListenableFuture提供了一个addCallback方法,可以在任务完成后执行onSuccess或onFailure回调。

Future.cancel()方法的作用和使用场景

Future.cancel() 方法用于尝试取消与 Future 关联的异步任务。它接收一个 Boolean 类型的参数 mayInterruptIfRunning,决定是否允许中断正在运行的任务。

  • mayInterruptIfRunning = true: 尝试中断正在运行的任务。这通常通过调用任务执行线程的 interrupt() 方法来实现。然而,任务是否真正响应中断取决于任务本身的实现。
  • mayInterruptIfRunning = false: 不允许中断正在运行的任务。如果任务尚未开始执行,则会被取消,否则任务会继续执行直到完成。

使用场景:

  • 资源释放: 当不再需要异步任务的结果时,可以调用 cancel() 方法来释放资源,避免不必要的计算。
  • 任务超时: 如果异步任务执行时间过长,超过了预期的阈值,可以使用 cancel() 方法来终止任务,防止资源被长时间占用。
  • 程序退出: 在程序退出前,可以尝试取消所有未完成的异步任务,确保资源得到正确释放。

需要注意的是,cancel() 方法并不保证任务一定会被取消。如果任务已经完成或已经被取消,调用 cancel() 方法不会产生任何影响。此外,即使 mayInterruptIfRunning 为 true,任务也可能忽略中断信号,继续执行直到完成。因此,在设计异步任务时,应该考虑如何优雅地处理中断信号,确保任务能够及时停止并释放资源。

FutureTask的原理和使用

FutureTask 是一个可取消的异步计算任务,它实现了 RunnableFuture 接口,该接口继承自 Runnable 和 Future。 这意味着 FutureTask 既可以作为一个 Runnable 提交给 ExecutorService 执行,也可以作为一个 Future 来获取异步计算的结果。

原理:

FutureTask 内部维护了一个状态机,用于表示任务的不同状态:

  • NEW: 任务创建后的初始状态。
  • COMPLETING: 任务正在完成,正在设置结果或抛出异常。
  • NORMAL: 任务正常完成,结果已设置。
  • EXCEPTIONAL: 任务执行过程中发生异常。
  • CANCELLED: 任务已被取消。
  • INTERRUPTING: 任务正在中断。
  • INTERRUPTED: 任务已被中断。

FutureTask 通过 run() 方法来执行任务。在 run() 方法中,它会调用任务的 call() 方法来执行实际的计算。计算结果会被保存,并将状态设置为 NORMAL 或 EXCEPTIONAL。

使用:

import java.util.concurrent.*;  public class FutureTaskExample {     public static void main(String[] args) throws InterruptedException, ExecutionException {         Callable<String> callable = () -> {             Thread.sleep(1000);             return "任务完成!";         };          FutureTask<String> futureTask = new FutureTask<>(callable);          ExecutorService executor = Executors.newSingleThreadExecutor();         executor.submit(futureTask);          System.out.println("任务提交...");          try {             String result = futureTask.get(); // 阻塞等待结果             System.out.println("结果: " + result);         } catch (InterruptedException | ExecutionException e) {             e.printStackTrace();         } finally {             executor.shutdown();         }     } }

这个例子展示了如何使用 FutureTask 来执行一个异步任务。首先,创建一个 Callable 对象,表示要执行的任务。然后,创建一个 FutureTask 对象,并将 Callable 对象传递给它。接下来,将 FutureTask 对象提交给 ExecutorService 执行。最后,通过 futureTask.get() 方法来获取异步计算的结果。

如何处理Future中的异常

处理 Future 中的异常主要有两种方式:

  1. 在 get() 方法中捕获异常: Future.get() 方法会抛出 InterruptedException 和 ExecutionException 两种异常。InterruptedException 表示当前线程在等待结果时被中断。ExecutionException 表示在任务执行过程中发生了异常。可以通过 try-catch 块来捕获这些异常,并进行相应的处理。
ExecutorService executor = Executors.newFixedThreadPool(1); Future<String> future = executor.submit(() -> {     // 模拟异常     throw new RuntimeException("任务执行出错!"); });  try {     String result = future.get();     System.out.println("结果: " + result); // 这行代码不会被执行 } catch (InterruptedException e) {     System.err.println("线程被中断: " + e.getMessage()); } catch (ExecutionException e) {     System.err.println("任务执行出错: " + e.getCause().getMessage()); } finally {     executor.shutdown(); }

在这个例子中,ExecutionException 的 getCause() 方法可以获取到原始的异常信息。

  1. 使用回调机制处理异常: 如前面提到的Guava的ListenableFuture,可以在回调函数中处理异常。
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors;  ExecutorService executor = Executors.newFixedThreadPool(1); ListenableFuture<String> future = MoreExecutors.listeningDecorator(executor).submit(() -> {     // 模拟异常     throw new RuntimeException("任务执行出错!"); });  Futures.addCallback(future, new FutureCallback<String>() {     @Override     public void onSuccess(String result) {         System.out.println("任务成功完成,结果: " + result); // 这行代码不会被执行     }      @Override     public void onFailure(Throwable t) {         System.err.println("任务失败: " + t.getMessage());     } }, MoreExecutors.directExecutor());  executor.shutdown();

使用回调机制可以更加灵活地处理异常,避免阻塞主线程。

Future与CompletableFuture的区别

Future 和 CompletableFuture 都是 Java 中用于处理异步计算结果的接口,但 CompletableFuture 是 Java 8 引入的,相比 Future 提供了更强大的功能和更灵活的编程模型。

  • 更丰富的 API: CompletableFuture 提供了更多的 API,可以进行链式调用、组合多个异步任务、处理异常等。Future 的 API 相对简单,只能获取结果和取消任务。
  • 非阻塞性: CompletableFuture 提供了非阻塞的 API,可以在任务完成时自动触发回调函数,避免了 Future.get() 方法的阻塞等待。
  • 组合性: CompletableFuture 可以将多个异步任务组合成一个新的异步任务,例如 thenApply()、thenCompose()、thenCombine() 等方法。
  • 异常处理: CompletableFuture 提供了更强大的异常处理机制,可以使用 exceptionally()、handle() 等方法来处理异步任务中的异常。
  • 更易于使用: CompletableFuture 的 API 设计更加友好,更容易使用和理解。

简单来说,CompletableFuture 是 Future 的增强版,提供了更多的功能和更灵活的编程模型,更适合构建复杂的异步应用。如果只需要简单的异步计算,可以使用 Future。如果需要更强大的功能和更灵活的编程模型,应该使用 CompletableFuture。

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享