日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java CompletableFuture詳解

在Java 8中, 新增加了一個包含50個方法左右的類: CompletableFuture,默認(rèn)依靠fork/join框架啟動新的線程實(shí)現(xiàn)異步與并發(fā)的,提供了非常強(qiáng)大的Future的擴(kuò)展功能,可以幫助我們簡化異步編程的復(fù)雜性,提供了函數(shù)式編程的能力,可以通過回調(diào)的方式處理計(jì)算結(jié)果,并且提供了轉(zhuǎn)換和組合CompletableFuture的方法。

CompletableFuture類實(shí)現(xiàn)了CompletionStage和Future接口,所以可以像以前一樣通過阻塞或者輪詢的方式獲得結(jié)果,盡管這種方式不推薦使用。

創(chuàng)建CompletableFuture對象。

以下四個靜態(tài)方法用來為一段異步執(zhí)行的代碼創(chuàng)建CompletableFuture對象:

 
 
 
 
  1. public static CompletableFuture              runAsync(Runnable runnable) 
  2.  
  3. public static CompletableFuture              runAsync(Runnable runnable, Executor executor) 
  4.  
  5. public static  CompletableFuture supplyAsync(Supplier supplier) 
  6.  
  7. public static  CompletableFuture supplyAsync(Supplier supplier, Executor executor) 

runAsync方法也好理解,它以Runnable函數(shù)式接口類型為參數(shù),所以CompletableFuture的計(jì)算結(jié)果為空。以Async結(jié)尾會使用其它的線程去執(zhí)行,沒有指定Executor的方法會使用ForkJoinPool.commonPool()作為它的線程池執(zhí)行異步代碼。

supplyAsync方法以Supplier函數(shù)式接口類型為參數(shù),CompletableFuture的計(jì)算結(jié)果類型為U。

因?yàn)榉椒ǖ膮?shù)類型都是函數(shù)式接口,所以可以使用lambda表達(dá)式實(shí)現(xiàn)異步任務(wù),比如:

 
 
 
 
  1. CompletableFuture future = CompletableFuture.supplyAsync(() -> { 
  2.  
  3.     //長時間的計(jì)算任務(wù) 
  4.  
  5.     return "hello world"; 
  6.  
  7. }); 

計(jì)算結(jié)果完成時的處理

當(dāng)CompletableFuture的計(jì)算結(jié)果完成,或者拋出異常的時候,我們可以執(zhí)行特定的Action。主要是下面的方法:

 
 
 
 
  1. public CompletableFuture  whenComplete(BiConsumer action) 
  2.  
  3. public CompletableFuture  whenCompleteAsync(BiConsumer action) 
  4.  
  5. public CompletableFuture  whenCompleteAsync(BiConsumer action, Executor executor) 
  6.  
  7. public CompletableFuture  exceptionally(Function fn) 

可以看到Action的類型是BiConsumer,它可以處理正常的計(jì)算結(jié)果,或者異常情況。

注意這幾個方法都會返回CompletableFuture,當(dāng)Action執(zhí)行完畢后它的結(jié)果返回原始的CompletableFuture的計(jì)算結(jié)果或者返回異常。

 
 
 
 
  1. public class Main { 
  2.  
  3.     private static Random rand = new Random(); 
  4.  
  5.     private static long t = System.currentTimeMillis(); 
  6.  
  7.     static int getMoreData() { 
  8.  
  9.         System.out.println("begin to start compute"); 
  10.  
  11.         try { 
  12.  
  13.             Thread.sleep(10000); 
  14.  
  15.         } catch (InterruptedException e) { 
  16.  
  17.             throw new RuntimeException(e); 
  18.  
  19.         } 
  20.  
  21.         System.out.println("end to start compute. passed " + (System.currentTimeMillis() - t)/1000 + " seconds"); 
  22.  
  23.         return rand.nextInt(1000); 
  24.  
  25.     } 
  26.  
  27.     public static void main(String[] args) throws Exception { 
  28.  
  29.         CompletableFuture future = CompletableFuture.supplyAsync(Main::getMoreData); 
  30.  
  31.         Future f = future.whenComplete((v, e) -> { 
  32.  
  33.             System.out.println(v); 
  34.  
  35.             System.out.println(e); 
  36.  
  37.         }); 
  38.  
  39.         System.out.println(f.get()); 
  40.  
  41.         System.in.read(); 
  42.  
  43.     } 
  44.  

exceptionally方法返回一個新的CompletableFuture,當(dāng)原始的CompletableFuture拋出異常的時候,就會觸發(fā)這個CompletableFuture的計(jì)算,調(diào)用function計(jì)算值,否則如果原始的CompletableFuture正常計(jì)算完后,這個新的CompletableFuture也計(jì)算完成,它的值和原始的CompletableFuture的計(jì)算的值相同。也就是這個exceptionally方法用來處理異常的情況。

結(jié)果轉(zhuǎn)換

由于回調(diào)風(fēng)格的實(shí)現(xiàn),我們不必因?yàn)榈却粋€計(jì)算完成而阻塞著調(diào)用線程,而是告訴CompletableFuture當(dāng)計(jì)算完成的時候請執(zhí)行某個function。而且我們還可以將這些操作串聯(lián)起來,或者將CompletableFuture組合起來。

 
 
 
 
  1. public  CompletableFuture  thenApply(Function fn) 
  2.  
  3. public  CompletableFuture  thenApplyAsync(Function fn) 
  4.  
  5. public  CompletableFuture  thenApplyAsync(Function fn, Executor executor) 

這一組函數(shù)的功能是當(dāng)原來的CompletableFuture計(jì)算完后,將結(jié)果傳遞給函數(shù)fn,將fn的結(jié)果作為新的CompletableFuture計(jì)算結(jié)果。因此它的功能相當(dāng)于將CompletableFuture轉(zhuǎn)換成CompletableFuture

使用例子如下:

 
 
 
 
  1. CompletableFuture future = CompletableFuture.supplyAsync(() -> { 
  2.  
  3.     return 100; 
  4.  
  5. }); 
  6.  
  7. CompletableFuture f =  future.thenApplyAsync(i -> i * 10).thenApply(i -> i.toString()); 
  8.  
  9. System.out.println(f.get()); //"1000" 

需要注意的是,這些轉(zhuǎn)換并不是馬上執(zhí)行的,也不會阻塞,而是在前一個stage完成后繼續(xù)執(zhí)行。

下面一組方法雖然也返回CompletableFuture對象,但是對象的值和原來的CompletableFuture計(jì)算的值不同。當(dāng)原先的CompletableFuture的值計(jì)算完成或者拋出異常的時候,會觸發(fā)這個CompletableFuture對象的計(jì)算,結(jié)果由BiFunction參數(shù)計(jì)算而得。因此這組方法兼有whenComplete和轉(zhuǎn)換的兩個功能。

 
 
 
 
  1. public  CompletableFuture     handle(BiFunction fn) 
  2.  
  3. public  CompletableFuture     handleAsync(BiFunction fn) 
  4.  
  5. public  CompletableFuture     handleAsync(BiFunction fn, Executor executor) 

它們與thenApply* 方法的區(qū)別在于handle*方法會處理正常計(jì)算值和異常,因此它可以屏蔽異常,避免異常繼續(xù)拋出。而thenApply*方法只是用來處理正常值,因此一旦有異常就會拋出。

純消費(fèi)結(jié)果

上面的方法是當(dāng)計(jì)算完成的時候,會生成新的計(jì)算結(jié)果(thenApply, handle),或者返回同樣的計(jì)算結(jié)果(whenComplete,CompletableFuture)。CompletableFuture提供了一種處理結(jié)果的方法,只對結(jié)果執(zhí)行Action,而不返回新的計(jì)算值,因此計(jì)算值為Void:

 
 
 
 
  1. public CompletableFuture  thenAccept(Consumer action) 
  2.  
  3. public CompletableFuture  thenAcceptAsync(Consumer action) 
  4.  
  5. public CompletableFuture  thenAcceptAsync(Consumer action, Executor executor) 

看它的參數(shù)類型也就明白了,它們是消費(fèi)型函數(shù)式接口Consumer,這個接口只有輸入,沒有返回值。

 
 
 
 
  1. CompletableFuture future = CompletableFuture.supplyAsync(() -> { 
  2.  
  3.     return 100; 
  4.  
  5. }); 
  6.  
  7. CompletableFuture f =  future.thenAccept(System.out::println); 
  8.  
  9. System.out.println(f.get()); 
  10.  
  11. public  CompletableFuture                thenAcceptBoth(CompletionStage other, BiConsumer action) 
  12.  
  13. public  CompletableFuture                thenAcceptBothAsync(CompletionStage other, BiConsumer action) 
  14.  
  15. public  CompletableFuture                thenAcceptBothAsync(CompletionStage other, BiConsumer action, Executor executor) 
  16.  
  17. public CompletableFuture  runAfterBoth(CompletionStage other,  Runnable action) 

thenAcceptBoth以及相關(guān)方法提供了類似的功能,當(dāng)兩個CompletionStage都正常完成計(jì)算的時候,就會執(zhí)行提供的action,它用來組合另外一個異步的結(jié)果。

runAfterBoth是當(dāng)兩個CompletionStage都正常完成計(jì)算的時候,執(zhí)行一個Runnable,這個Runnable并不使用計(jì)算的結(jié)果。

例子如下:

 
 
 
 
  1. CompletableFuture future = CompletableFuture.supplyAsync(() -> { 
  2.  
  3.     return 100; 
  4.  
  5. }); 
  6.  
  7. CompletableFuture f =  future.thenAcceptBoth(CompletableFuture.completedFuture(10), (x, y) -> System.out.println(x * y)); 
  8.  
  9. System.out.println(f.get()); 

更徹底地,下面一組方法當(dāng)計(jì)算完成的時候會執(zhí)行一個Runnable,與thenAccept不同,Runnable并不使用CompletableFuture計(jì)算的結(jié)果。

 
 
 
 
  1. public CompletableFuture  thenRun(Runnable action) 
  2.  
  3. public CompletableFuture  thenRunAsync(Runnable action) 
  4.  
  5. public CompletableFuture  thenRunAsync(Runnable action,  Executor executor) 

因此先前的CompletableFuture計(jì)算的結(jié)果被忽略了,這個方法返回CompletableFuture類型的對象。

 
 
 
 
  1. CompletableFuture future = CompletableFuture.supplyAsync(() -> { 
  2.  
  3.     return 100; 
  4.  
  5. }); 
  6.  
  7. CompletableFuture f =  future.thenRun(() -> System.out.println("finished")); 
  8.  
  9. System.out.println(f.get()); 

因此,你可以根據(jù)方法的參數(shù)的類型來加速你的記憶。Runnable類型的參數(shù)會忽略計(jì)算的結(jié)果,Consumer是純消費(fèi)計(jì)算結(jié)果,BiConsumer會組合另外一個CompletionStage純消費(fèi),F(xiàn)unction會對計(jì)算結(jié)果做轉(zhuǎn)換,BiFunction會組合另外一個CompletionStage的計(jì)算結(jié)果做轉(zhuǎn)換。

組合

有時,你需要在一個future結(jié)構(gòu)運(yùn)行某個函數(shù),但是這個函數(shù)也是返回某種future,也就是說是兩個future彼此依賴串聯(lián)在一起,它類似于flatMap。

 
 
 
 
  1. public  CompletableFuture  thenCompose(Function> fn) 
  2.  
  3. public  CompletableFuture  thenComposeAsync(Function> fn) 
  4.  
  5. public  CompletableFuture  thenComposeAsync(Function> fn,  Executor executor) 

這一組方法接受一個Function作為參數(shù),這個Function的輸入是當(dāng)前的CompletableFuture的計(jì)算值,返回結(jié)果將是一個新的CompletableFuture,這個新的CompletableFuture會組合原來的CompletableFuture和函數(shù)返回的CompletableFuture。因此它的功能類似:

A +--> B +---> C

記住,thenCompose返回的對象并不一是函數(shù)fn返回的對象,如果原來的CompletableFuture還沒有計(jì)算出來,它就會生成一個新的組合后的CompletableFuture。

例子:

 
 
 
 
  1. CompletableFuture future = CompletableFuture.supplyAsync(() -> { 
  2.  
  3.     return 100; 
  4.  
  5. }); 
  6.  
  7. CompletableFuture f =  future.thenCompose( i -> { 
  8.  
  9.     return CompletableFuture.supplyAsync(() -> { 
  10.  
  11.         return (i * 10) + ""; 
  12.  
  13.     }); 
  14.  
  15. }); 
  16.  
  17. System.out.println(f.get()); //1000 

而下面的一組方法thenCombine用來復(fù)合另外一個CompletionStage的結(jié)果。它的功能類似:

A +

  |

  +------> C

  +------^

B +

兩個CompletionStage是并行執(zhí)行的,它們之間并沒有先后依賴順序,other并不會等待先前的CompletableFuture執(zhí)行完畢后再執(zhí)行。

 
 
 
 
  1. public  CompletableFuture thenCombine(CompletionStage other, BiFunction fn) 
  2.  
  3. public  CompletableFuture thenCombineAsync(CompletionStage other, BiFunction fn) 
  4.  
  5. public  CompletableFuture thenCombineAsync(CompletionStage other, BiFunction fn, Executor executor) 

其實(shí)從功能上來講,它們的功能更類似thenAcceptBoth,只不過thenAcceptBoth是純消費(fèi),它的函數(shù)參數(shù)沒有返回值,而thenCombine的函數(shù)參數(shù)fn有返回值。

 
 
 
 
  1. CompletableFuture future = CompletableFuture.supplyAsync(() -> { 
  2.  
  3.     return 100; 
  4.  
  5. }); 
  6.  
  7. CompletableFuture future2 = CompletableFuture.supplyAsync(() -> { 
  8.  
  9.     return "abc"; 
  10.  
  11. }); 
  12.  
  13. CompletableFuture f =  future.thenCombine(future2, (x,y) -> y + "-" + x); 
  14.  
  15. System.out.println(f.get()); //abc-100 

Either

thenAcceptBoth和runAfterBoth是當(dāng)兩個CompletableFuture都計(jì)算完成,而我們下面要了解的方法是當(dāng)任意一個CompletableFuture計(jì)算完成的時候就會執(zhí)行。

 
 
 
 
  1. public CompletableFuture        acceptEither(CompletionStage other, Consumer action) 
  2.  
  3. public CompletableFuture        acceptEitherAsync(CompletionStage other, Consumer action) 
  4.  
  5. public CompletableFuture        acceptEitherAsync(CompletionStage other, Consumer action, Executor executor) 
  6.  
  7. public  CompletableFuture     applyToEither(CompletionStage other, Function fn) 
  8.  
  9. public  CompletableFuture     applyToEitherAsync(CompletionStage other, Function fn) 
  10.  
  11. public  CompletableFuture     applyToEitherAsync(CompletionStage other, Function fn, Executor executor) 

acceptEither方法是當(dāng)任意一個CompletionStage完成的時候,action這個消費(fèi)者就會被執(zhí)行。這個方法返回CompletableFuture

applyToEither方法是當(dāng)任意一個CompletionStage完成的時候,fn會被執(zhí)行,它的返回值會當(dāng)作新的CompletableFuture的計(jì)算結(jié)果。

下面這個例子有時會輸出100,有時候會輸出200,哪個Future先完成就會根據(jù)它的結(jié)果計(jì)算。

 
 
 
 
  1. Random rand = new Random(); 
  2.  
  3. CompletableFuture future = CompletableFuture.supplyAsync(() -> { 
  4.  
  5.     try { 
  6.  
  7.         Thread.sleep(10000 + rand.nextInt(1000)); 
  8.  
  9.     } catch (InterruptedException e) { 
  10.  
  11.         e.printStackTrace(); 
  12.  
  13.     } 
  14.  
  15.     return 100; 
  16.  
  17. }); 
  18.  
  19. CompletableFuture future2 = CompletableFuture.supplyAsync(() -> { 
  20.  
  21.     try { 
  22.  
  23.         Thread.sleep(10000 + rand.nextInt(1000)); 
  24.  
  25.     } catch (InterruptedException e) { 
  26.  
  27.         e.printStackTrace(); 
  28.  
  29.     } 
  30.  
  31.     return 200; 
  32.  
  33. }); 
  34.  
  35. CompletableFuture f =  future.applyToEither(future2,i -> i.toString());  

輔助方法 allOf 和 anyOf

前面我們已經(jīng)介紹了幾個靜態(tài)方法:completedFuture、runAsync、supplyAsync,下面介紹的這兩個方法用來組合多個CompletableFuture。

 
 
 
 
  1. public static CompletableFuture  allOf(CompletableFuture... cfs) 
  2.  
  3. public static CompletableFuture  anyOf(CompletableFuture... cfs) 

    allOf方法是當(dāng)所有的CompletableFuture都執(zhí)行完后執(zhí)行計(jì)算。

    anyOf方法是當(dāng)任意一個CompletableFuture執(zhí)行完后就會執(zhí)行計(jì)算,計(jì)算的結(jié)果相同。

    下面的代碼運(yùn)行結(jié)果有時是100,有時是"abc"。但是anyOf和applyToEither不同。anyOf接受任意多的CompletableFuture,但是applyToEither只是判斷兩個CompletableFuture。anyOf返回值的計(jì)算結(jié)果是參數(shù)中其中一個CompletableFuture的計(jì)算結(jié)果,applyToEither返回值的計(jì)算結(jié)果卻是要經(jīng)過fn處理的。當(dāng)然還有靜態(tài)方法的區(qū)別,線程池的選擇等。

     
     
     
     
    1. Random rand = new Random(); 
    2.  
    3. CompletableFuture future1 = CompletableFuture.supplyAsync(() -> { 
    4.  
    5.     try { 
    6.  
    7.         Thread.sleep(10000 + rand.nextInt(1000)); 
    8.  
    9.     } catch (InterruptedException e) { 
    10.  
    11.         e.printStackTrace(); 
    12.  
    13.     } 
    14.  
    15.     return 100; 
    16.  
    17. }); 
    18.  
    19. CompletableFuture future2 = CompletableFuture.supplyAsync(() -> { 
    20.  
    21.     try { 
    22.  
    23.         Thread.sleep(10000 + rand.nextInt(1000)); 
    24.  
    25.     } catch (InterruptedException e) { 
    26.  
    27.         e.printStackTrace(); 
    28.  
    29.     } 
    30.  
    31.     return "abc"; 
    32.  
    33. }); 
    34.  
    35. //CompletableFuture f =  CompletableFuture.allOf(future1,future2); 
    36.  
    37. CompletableFuture f =  CompletableFuture.anyOf(future1,future2); 
    38.  
    39. System.out.println(f.get()); 
    40. 更進(jìn)一步

      Guava的Future類,它的Futures輔助類提供了很多便利方法,用來處理多個Future,而不像Java的CompletableFuture,只提供了allOf、anyOf兩個方法。 比如有這樣一個需求,將多個CompletableFuture組合成一個CompletableFuture,這個組合后的CompletableFuture的計(jì)算結(jié)果是個List,它包含前面所有的CompletableFuture的計(jì)算結(jié)果,guava的Futures.allAsList可以實(shí)現(xiàn)這樣的功能,但是對于java CompletableFuture,我們需要一些輔助方法:

       
       
       
       
      1. public static  CompletableFuture> sequence(List> futures) { 
      2.  
      3.        CompletableFuture allDoneFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])); 
      4.  
      5.        return allDoneFuture.thenApply(v -> futures.stream().map(CompletableFuture::join).collect(Collectors.toList())); 
      6.  
      7.    } 
      8.  
      9. public static  CompletableFuture> sequence(Stream> futures) { 
      10.  
      11.        List> futureList = futures.filter(f -> f != null).collect(Collectors.toList()); 
      12.  
      13.        return sequence(futureList); 
      14.  
      15.    } 

      或者Java Future轉(zhuǎn)CompletableFuture:

       
       
       
       
      1.  public static  CompletableFuture toCompletable(Future future, Executor executor) { 
      2.     return CompletableFuture.supplyAsync(() -> { 
      3.  
      4.         try { 
      5.  
      6.             return future.get(); 
      7.  
      8.         } catch (InterruptedException | ExecutionException e) { 
      9.  
      10.             throw new RuntimeException(e); 
      11.  
      12.         } 
      13.  
      14.     }, executor); 
      15.  

      網(wǎng)站標(biāo)題:Java CompletableFuture詳解
      文章起源:http://www.5511xx.com/article/cdggjig.html