有點經驗的工程師必定對多線程比較熟悉,JDK封裝的FutureTask實現了這一功能。以下圖:web
FutureTask實現了RunnableFuture接口,而RunnableFuture接口繼承了Future+Runnable共2個接口。所以,FutureTask支持線程執行任務run(),也支持get()等待任務完成、cancel()取消任務等。可是明顯仍是不夠。服務器
Guava的併發包,強大而簡單的抽象,讓編寫正確的併發代碼更簡單多線程
ListenableFuture接口並繼承了JDK concurrent包下的Future 接口。配合Futures工具類,能夠很方便的實現如下功能:併發
1)監放任務執行結果並執行回調方法。app
2)提供方便的任務接口轉換。框架
3)多線程併發執行取結果集合。異步
抽象可開啓和關閉的服務,幫助你維護服務的狀態邏輯ide
1)定義監聽執行器。工具
2)定義可監聽的帶返回值任務。spa
3)定義回調方法。
3)綁定任務、執行器、回調方法。
1 public static void main(String[] args) throws ExecutionException, InterruptedException { 2 /** 1.典型用法:可監聽的future,帶回調方法 */ 3 // 定義監聽執行服務 4 ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)); 5 // 定義可監聽的帶返回值的任務 6 ListenableFuture<String> callableListenableFuture1 = listeningExecutorService.submit(() -> { 7 System.out.println("callable1 call!"); 8 return "1"; 9 }); 10 // 添加回調,由指定監聽執行服務來執行,監聽可監聽的future,監聽到事件時執行對應回調方法。 11 Futures.addCallback(callableListenableFuture1, new FutureCallback<String>() { 12 @Override 13 public void onSuccess(@Nullable String result) { 14 System.out.println("success,result=" + result); 15 } 16 17 @Override 18 public void onFailure(Throwable t) { 19 System.out.println("fail!"); 20 } 21 }, listeningExecutorService); 22 }
callable1 call!
success,result=1
1) 定義一個須要綁定的ListenableFuture
2)定義一個異步轉換方法
3)定義一個線程任務執行器
4)調用Futures工具類的transformAsync方法實現轉換
1 public static void main(String[] args) throws ExecutionException, InterruptedException { 2 /** 2.非典型用法:異步轉換 */ 3 // 異步轉換,參數1是須要轉換的listenableFuture,參數2是轉換方法,參數3是執行轉換的線程執行器(Runnable)。 4 ListenableFuture<Integer> transform = Futures.transformAsync(callableListenableFuture1, new AsyncFunction<String, Integer>() { 5 @Override 6 public ListenableFuture<Integer> apply(@Nullable String input) { 7 return Futures.immediateFuture(Integer.parseInt(input)); 8 } 9 }, MoreExecutors.directExecutor()); 10 // 阻塞線程獲得結果 11 System.out.println("阻塞獲取轉換後任務的結果:"+transform.get()); 12 }
阻塞獲取轉換後任務的結果:1
1)定義多個任務
2)調用Futures工具類的allAsList方法合併結果,返回一個總ListenableFuture,調用get方法便可實現多線程併發執行任務取結果集合,結果是list,順序是按照提交任務的順序。
1 public static void main(String[] args) throws ExecutionException, InterruptedException { 2 /** 3.典型用法:多任務併發執行取結果list */ 3 // 可監聽不帶返回值的任務 4 5 ListenableFuture<String> callableListenableFuture2 = listeningExecutorService.submit(() -> { 6 Thread.sleep(3000); 7 System.out.println("callable2 call!"); 8 return "2"; 9 }); 10 ListenableFuture<String> callableListenableFuture3 = listeningExecutorService.submit(() -> { 11 System.out.println("callable3 call!"); 12 return "3"; 13 }); 14 ListenableFuture<List<String>> listListenableFuture = Futures.allAsList( 15 Lists.newArrayList(callableListenableFuture1, callableListenableFuture2, callableListenableFuture3)); 16 // 返回結果list就是添加任務的順序 17 System.out.println("多任務併發執行取結果list result=" + listListenableFuture.get()); 18 }
callable1 call!
callable3 call! callable2 call! 多任務併發執行取結果list result=[1, 2, 3]
Guava包裏的Service接口用於封裝一個服務對象的運行狀態,包括start和stop等方法。例如web服務器,RPC服務器、計時器等能夠實現這個接口。對此類服務的狀態管理在多線程環境下尤其複雜。Guava包提供了一些基礎類幫助你管理複雜的狀態轉換邏輯和同步細節。這裏不細節拓展,不多狀況會用到這個框架。
Guava 提供了ListenableFuture接口,結合Futures工具類,能夠很是方便的實現併發任務,取結果list等方法,且API優雅易用,在特定場景,建議使用。
相反,Service框架,可能重量級的業務場景纔可能使用到,簡單場景沒有必要使用。