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 分享