併發程式設計--常用方法以及CompletableFuture

敲出快樂發表於2020-11-23

常用方法

  • 宣告一個ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

  • ExecutorService方式:execute方法 new Runnable() 這樣可以非同步的執行Runnable裡面的方法。

//非同步方式一
    @Override
    public void get1() {
        System.out.println("非同步1");
        newCachedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                get4();
            }
        });
    }
  • 使用註解方式(需要spring掃描) 啟動類打上@EnableAsync註解開啟非同步
    在這裡插入圖片描述
  • 非同步方法加上@Async 標識這是一個非同步方法
    在這裡插入圖片描述
  • 控制層呼叫該方法,就會非同步執行
    在這裡插入圖片描述

CompletableFuture常用方法

  • CompletableFuture類實現了CompletionStage和Future介面。Future是Java 5新增的類,用來描述一個非同步計算的結果,
  • 但是獲取一個結果時方法較少,要麼通過輪詢isDone,確認完成後,呼叫get()獲取值,要麼呼叫get()設定一個超時時間。
  • 但是這個get()方法會阻塞住呼叫執行緒,這種阻塞的方式顯然和我們的非同步程式設計的初衷相違背。
  • 為了解決這個問題,JDK吸收了guava的設計思想,加入了Future的諸多擴充套件功能形成了CompletableFuture。
  • /*
    已Async結尾的方法都是可以非同步執行的,如果指定了執行緒池,會在指定的執行緒池中執行,如果沒有指定,預設會在ForkJoinPool.commonPool()中執行。
    關鍵的入參只有一個Function,它是函式式介面,所以使用Lambda表示.
    /
    /
    *
    • 入參是上一個階段計算後的結果,返回值是經過轉化後結果。
    • public CompletionStage thenApply(Function<? super T,? extends U> fn);
    • public CompletionStage thenApplyAsync(Function<? super T,? extends U> fn);
    • public CompletionStage thenApplyAsync(Function<? super T,? extends U> fn,Executor executor);
      */

    @Test
    public void thenApply() {
        String result = CompletableFuture.supplyAsync(() -> "hello").thenApply(s -> s + " world").join();
        System.out.println(result);
    }

    @Test
    public void thenApplyAsync() {
        String result = CompletableFuture.supplyAsync(() -> "hello").thenApplyAsync(s -> s + " world").join();
        System.out.println(result);
    }

    @Test
    public void thenApplyAsyncAndExecutor() {
        String result = CompletableFuture.supplyAsync(() -> "hello").thenApplyAsync(s -> s + " world", newCachedThreadPool).join();
        System.out.println(result);
    }

/**
* thenAccept是針對結果進行消耗,因為他的入參是Consumer,有入參無返回值。
* public CompletionStage thenAccept(Consumer<? super T> action);
* public CompletionStage thenAcceptAsync(Consumer<? super T> action);
* public CompletionStage thenAcceptAsync(Consumer<? super T> action,Executor executor);
*/

@Test
    public void thenAccept() {
        CompletableFuture.supplyAsync(() -> "hello").thenAccept(s -> System.out.println(s + " world"));
    }

/**
* 對上一步的計算結果不關心,執行下一個操作。
* public CompletionStage thenRun(Runnable action);
* public CompletionStage thenRunAsync(Runnable action);
* public CompletionStage thenRunAsync(Runnable action,Executor executor);
*/

@Test
public void thenRun() {
    CompletableFuture.supplyAsync(() -> {
        int i=1+1;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello";
    }).thenRunAsync(() -> System.out.println("hello world"),newCachedThreadPool);
    while (true) {
    }
}

@Test
public void thenRunAsync() {
    CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello";
    }).thenRun(() -> System.out.println("hello world"));
    while (true) {
    }
}

@Test
public void thenRunAsyncAndExecutor() {
    CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello";
    }).thenRunAsync(() -> System.out.println("hello world"), newCachedThreadPool);
    while (true) {
    }
}

/**
* 結合兩個CompletionStage的結果,進行轉化後返回
* public <U,V> CompletionStage thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
* public <U,V> CompletionStage thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
* public <U,V> CompletionStage thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);
* 它需要原來的處理返回值,並且other代表的CompletionStage也要返回值之後,利用這兩個返回值,進行轉換後返回指定型別的值。
*/

  @Test
    public void thenCombine() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello";
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "world";
        }), (s1, s2) -> s1 + " " + s2).join();
        System.out.println(result);
    }

/**
* 結合兩個CompletionStage的結果,進行消耗
* public CompletionStage thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
* public CompletionStage thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
* public CompletionStage thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor);
* 它需要原來的處理返回值,並且other代表的CompletionStage也要返回值之後,利用這兩個返回值,進行消耗。
*/

  @Test
    public void thenAcceptBoth() {
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello";
        }).thenAcceptBoth(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "world";
        }), (s1, s2) -> System.out.println(s1 + " " + s2));
        while (true) {
        }
    }

/**
* 在兩個CompletionStage都執行完執行。
* public CompletionStage runAfterBoth(CompletionStage<?> other,Runnable action);
* public CompletionStage runAfterBothAsync(CompletionStage<?> other,Runnable action);
* public CompletionStage runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor);
* 不關心這兩個CompletionStage的結果,只關心這兩個CompletionStage執行完畢,之後在進行操作(Runnable)。
*/

 @Test
    public void runAfterBoth() {
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s1";
        }).runAfterBothAsync(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s2";
        }), () -> System.out.println("hello world"));
        while (true) {
        }
    }

/**
* 兩個CompletionStage,誰計算的快,我就用那個CompletionStage的結果進行下一步的轉化操作。
* public CompletionStage applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);
* public CompletionStage applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);
* public CompletionStage applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn,Executor executor);
* 碰到有兩種渠道完成同一個事情,所以就可以呼叫這個方法,找一個最快的結果進行處理。
*/

  @Test
    public void applyToEither() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s1";
        }).applyToEither(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello world";
        }), s -> s).join();
        System.out.println(result);
    }

/**
* 兩個CompletionStage,任何一個完成了都會執行下一步的操作(Runnable)
* public CompletionStage runAfterEither(CompletionStage<?> other,Runnable action);
* public CompletionStage runAfterEitherAsync(CompletionStage<?> other,Runnable action);
* public CompletionStage runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);
*/

 @Test
    public void runAfterEither() {
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s1";
        }).runAfterEither(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s2";
        }), () -> System.out.println("hello world"));
        while (true) {
        }
    }

/**
* 當執行時出現了異常,可以通過exceptionally進行補償
* public CompletionStage exceptionally(Function<Throwable, ? extends T> fn);
*/

 @Test
    public void exceptionally() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (1 == 1) {
                throw new RuntimeException("測試一下異常情況");
            }
            return "s1";
        }).exceptionally(e -> {
            System.out.println(e.getMessage());
            return "hello world";
        }).join();
        System.out.println(result);
    }

/**
* 當執行完成時,對結果的記錄。這裡的完成時有兩種情況,一種是正常執行,返回值。另外一種是遇到異常丟擲造成程式的中斷。
* 這裡為什麼要說成記錄,因為這幾個方法都會返回CompletableFuture,
* 當Action執行完畢後它的結果返回原始的CompletableFuture的計算結果或者返回異常。所以不會對結果產生任何的作用。
* public CompletionStage whenComplete(BiConsumer<? super T, ? super Throwable> action);
* public CompletionStage whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action);
* public CompletionStage whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action,Executor executor);
*/

   @Test
    public void whenComplete() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (1 == 1) {
                throw new RuntimeException("測試一下異常情況");
            }
            return "s1";
        }).whenComplete((s, t) -> {
            System.out.println(s);
            System.out.println(t.getMessage());
        }).exceptionally(e -> {
            System.out.println(e.getMessage());
            return "hello world";
        }).join();
        System.out.println(result);
    }

//這裡也可以看出,如果使用了exceptionally,就會對最終的結果產生影響,它沒有口子返回如果沒有異常時的正確的值,這也就引出下面我們要介紹的handle。

/**
 * 執行完成時,對結果的處理。這裡的完成時有兩種情況,一種是正常執行,返回值。另外一種是遇到異常丟擲造成程式的中斷。
 * public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
 * public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
 * public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Executor executor);
 */
  //出現異常時
    @Test
    public void handleHasException() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //出現異常
            if (1 == 1) {
                throw new RuntimeException("測試一下異常情況");
            }
            return "s1";
        }).handle((s, t) -> {
            if (t != null) {
                return "hello world";
            }
            return s;
        }).join();
        System.out.println(result);
    }

    //未出現異常時
    @Test
    public void handle() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s1";
        }).handle((s, t) -> {
            if (t != null) {
                return "hello world";
            }
            return s;
        }).join();
        System.out.println(result);
    }

    //方法非同步執行
    @Test
    public void test2() throws Exception {
        System.out.println("main函式開始執行");
        ExecutorService executor = Executors.newFixedThreadPool(2);
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                System.out.println("===task start===");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("===task finish===");
                return 3;
            }
        }, executor);
        future.thenAccept(e -> System.out.println(e));
        System.out.println("main函式執行結束");
    }

相關文章