ListenableFuture是可以監聽的Future,它是對Java原生的Future進行了拓展和增強。在java中Future表示一個多線程異步執行的任務,當任務執行完成之後可以得到一個計算結果。如果我們希望一旦計算完成之後就可以拿到結果返回或者將結果做另外的計算操作,就必須使用線程去不斷查詢計算狀態。這樣做會導致代碼複雜,並且計算效率低下。使用ListenableFuture Guava幫我們檢測Future是否完成了,如果完成就自動調用回調函數,這樣可以減少併發程序的複雜度。
ListenableFuture回調函數有兩種方式:
1.通過ListenableFuture的addListener方法
ListenableFuture是一個接口,它從jdk的Future接口繼承,添加了void addListener(Runnable listener, Executor executor)
方法。
2.通過Futures的靜態方法addCallback給ListenableFuture添加回調函數
在調用回調函數之前,首先需要實例化ListenableFuture實例對象。
ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5)); ListenableFutureTest test1 = new ListenableFutureTest(); //獲取一個ListenableFuture對象 ListenableFuture<Integer> listenableFuture = listeningExecutorService.submit(test1);
首先通過MoreExecutors類的靜態方法listeningDecorator方法初始化一個ListeningExecutorService的方法,然後使用此實例的submit方法即可初始化ListenableFuture對象。
方式1:通過ListenableFuture的addListener方法
代碼實例:
private static AtomicInteger count = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException { ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5)); ListenableFutureTest test1 = new ListenableFutureTest(); //獲取一個ListenableFuture對象 ListenableFuture<Integer> listenableFuture = listeningExecutorService.submit(test1); listenableFuture.addListener(new Runnable() { @Override public void run() { try { System.out.println("線程執行完成後執行該回調函數,線程返回值爲:" + listenableFuture.get()); }catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }, listeningExecutorService); } @Override public Integer call() throws Exception { while (count.get() < 100) { count.getAndIncrement(); System.out.println(Thread.currentThread().getName() + ":" + count.get()); Thread.sleep(10); } return count.get(); }
2.通過Futures的靜態方法addCallback給ListenableFuture添加回調函數
1 public static void main(String[] args) throws InterruptedException { 2 ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5)); 3 ListenableFutureTest test1 = new ListenableFutureTest(); 4 //獲取一個ListenableFuture對象 5 ListenableFuture<Integer> listenableFuture = listeningExecutorService.submit(test1); 6 //使用addCallback方法 7 Futures.addCallback(listenableFuture, new FutureCallback<Integer>() { 8 9 @Override 10 public void onSuccess(Integer result) { 11 System.out.println(Thread.currentThread().getName() + "線程執行結束,返回結果:" + result); 12 } 13 14 @Override 15 public void onFailure(Throwable t) { 16 t.printStackTrace(); 17 } 18 }); 19 }
當發生異常時:
1 public static void main(String[] args) throws InterruptedException { 2 ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5)); 3 ListenableFutureTest test1 = new ListenableFutureTest(); 4 //獲取一個ListenableFuture對象 5 ListenableFuture<Integer> listenableFuture = listeningExecutorService.submit(test1); 6 Futures.addCallback(listenableFuture, new FutureCallback<Integer>() { 7 8 @Override 9 public void onSuccess(Integer result) { 10 System.out.println(Thread.currentThread().getName() + "線程執行結束,返回結果:" + result); 11 } 12 13 @Override 14 public void onFailure(Throwable t) { 15 System.out.println(Thread.currentThread().getName() + "線程執行發生異常"); 16 t.printStackTrace(); 17 } 18 }); 19 } 20 21 @Override 22 public Integer call() throws Exception { 23 while (count.get() < 100) { 24 count.getAndIncrement(); 25 System.out.println(Thread.currentThread().getName() + ":" + count.get()); 26 Thread.sleep(10); 27 if (count.get() == 20) { 28 throw new InterruptedException("異常測試"); 29 } 30 } 31 return count.get(); 32 }
當發生異常時,回調函數輸出結果爲:
推薦使用第二種方法,因爲第二種方法可以直接得到Future的返回值,或者處理錯誤情況。本質上第二種方法是通過調動第一種方法實現的,做了進一步的封裝。
另外ListenableFuture還有其他幾種內置實現:
- SettableFuture:不需要實現一個方法來計算返回值,而只需要返回一個固定值來做爲返回值,可以通過程序設置此Future的返回值或者異常信息
- CheckedFuture: 這是一個繼承自ListenableFuture接口,他提供了checkedGet()方法,此方法在Future執行發生異常時,可以拋出指定類型的異常。