java8 -- 異步編程

一:創建任務並執行任務

1:無參創建:CompletableFuture<String> noArgsFuture = new CompletableFuture<>();

2:傳入相應任務,無返回值(runAsync方法可以在後臺執行異步計算,但是此時並沒有返回值。持有一個Runnable對象。)

CompletableFuture noReturn = CompletableFuture.runAsync(()->{
    //執行邏輯,無返回值
});

3:傳入相應任務,有返回值;(此時我們看到返回的是CompletableFuture<T>此處的T就是你想要的返回值的類型。其中的Supplier<T>是一個簡單的函數式接口。)

CompletableFuture<String> hasReturn = CompletableFuture.supplyAsync(new Supplier<String>() {
    @Override
    public String get() {
        return "hasReturn";
    }
});

         此時可以使用lambda表達式使上面的邏輯更加清晰:get方法獲取返回結果

CompletableFuture<String> hasReturnLambda = CompletableFuture.supplyAsync(TestFuture::get);

 3:獲取返回值(異步任務也是有返回值的,當我們想要用到異步任務的返回值時,我們可以調用CompletableFutureget()阻塞,直到有異步任務執行完有返回值才往下執行)

4:自定義返回值(我們也可以在任意時候調用complete()方法來自定義返回值)

CompletableFuture<String> future1 = new CompletableFuture<>();
        System.out.println("main method is invoking");
        try {
            new Thread(()->{
                System.out.println("thread is invoking");
                try {
                    Thread.sleep(5000);
                    future1.complete("123456");
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("thread is end");


            }).run();
            System.out.println("Main Method End value is " + future1.get());
        }catch (Exception e){
            e.printStackTrace();
        }

 

二:按順序執行異步任務

如果有一個異步任務的完成需要依賴前一個異步任務的完成,那麼該如何寫呢?是調用get()方法獲得返回值以後然後再執行嗎?這樣寫有些麻煩,CompletableFuture爲我們提供了方法來完成我們想要順序執行一些異步任務的需求。thenApplythenAcceptthenRun這三個方法。這三個方法的區別就是。

一般來說thenAcceptthenRun這兩個方法在調用鏈的最末端使用。實例如下: 

 // thenApply  可獲取前一個任務的返回值,自身也有返回值
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "one");
        CompletableFuture<String> future2 = future1.thenApply(name -> name + "two");
        try{
            System.out.println(future2.get());
        }catch (Exception e){
            e.printStackTrace();
        }


        // thenAccept 可獲取前一個任務的返回值,但是自身沒有返回值
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "three");
        future3.thenAccept(name -> System.out.println(name + "thenAccept"));
        System.out.println("----------------------");

        try{
            System.out.println(future3.get());
        }catch (Exception e){
            e.printStackTrace();
        }

        //thenRun 獲取不到前一個任務的返回值,也無返回值
        System.out.println("-------------");
        CompletableFuture<Void> thenRun = future3.thenRun(() -> {
            System.out.println("thenRun");
        });
        try{
            System.out.println(thenRun.get());
        }catch (Exception e){
            e.printStackTrace();
        }

1:thenApply和thenApplyAsync的區別 

如果使用thenApplyAsync,那麼執行的線程是從ForkJoinPool.commonPool()中獲取不同的線程進行執行,如果使用thenApply,如果supplyAsync方法執行速度特別快,那麼thenApply任務就是主線程進行執行,如果執行特別慢的話就是和supplyAsync執行線程一樣。接下來我們通過例子來看一下,使用sleep方法來反應supplyAsync執行速度的快慢。

//thenApply和thenApplyAsync的區別
System.out.println("-------------");
CompletableFuture<String> supplyAsyncWithSleep = CompletableFuture.supplyAsync(()->{
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "supplyAsyncWithSleep Thread Id : " + Thread.currentThread();
});
CompletableFuture<String> thenApply = supplyAsyncWithSleep
        .thenApply(name -> name + "------thenApply Thread Id : " + Thread.currentThread());
CompletableFuture<String> thenApplyAsync = supplyAsyncWithSleep
        .thenApplyAsync(name -> name + "------thenApplyAsync Thread Id : " + Thread.currentThread());
System.out.println("Main Thread Id: "+ Thread.currentThread());
System.out.println(thenApply.get());
System.out.println(thenApplyAsync.get());
System.out.println("-------------No Sleep");
CompletableFuture<String> supplyAsyncNoSleep = CompletableFuture.supplyAsync(()->{
    return "supplyAsyncNoSleep Thread Id : " + Thread.currentThread();
});
CompletableFuture<String> thenApplyNoSleep = supplyAsyncNoSleep
        .thenApply(name -> name + "------thenApply Thread Id : " + Thread.currentThread());
CompletableFuture<String> thenApplyAsyncNoSleep = supplyAsyncNoSleep
        .thenApplyAsync(name -> name + "------thenApplyAsync Thread Id : " + Thread.currentThread());
System.out.println("Main Thread Id: "+ Thread.currentThread());
System.out.println(thenApplyNoSleep.get());
System.out.println(thenApplyAsyncNoSleep.get());

三:組合CompletableFuture 

 將兩個CompletableFuture組合在一起有兩個方法:

  1. thenCompose():當第一個任務完成時纔會執行第二個操作
  2. thenCombine():兩個異步任務全部完成時纔會執行某些操作

 thenCompose() 用法:

定義兩個異步任務,假設第二個定時任務需要用到第一個定時任務的返回值。

public static CompletableFuture<String> getTastOne(){
    return CompletableFuture.supplyAsync(()-> "topOne");
}

public static CompletableFuture<String> getTastTwo(String s){
    return CompletableFuture.supplyAsync(()-> s + "  topTwo");
}

利用thenCompose()方法進行編寫

CompletableFuture<String> thenComposeComplet = getTastOne().thenCompose(s -> getTastTwo(s));
System.out.println(thenComposeComplet.get());

// 輸出: topOne  topTwo

thenCombine() 用法:

例如我們此時需要計算兩個異步方法返回值的和。求和這個操作是必須是兩個異步方法得出來值的情況下才能進行計算,因此我們可以用thenCombine()方法進行計算。

CompletableFuture<Integer> thenComposeOne = CompletableFuture.supplyAsync(() -> 192);
CompletableFuture<Integer> thenComposeTwo = CompletableFuture.supplyAsync(() -> 196);
CompletableFuture<Integer> thenComposeCount = thenComposeOne
        .thenCombine(thenComposeTwo, (s, y) -> s + y);
System.out.println(thenComposeCount.get());

此時thenComposeOnethenComposeTwo都完成時纔會調用傳給thenCombine方法的回調函數。 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章