springbootCompletableFuture非同期スレッドプール

この記事は、「新人クリエーションセレモニー」イベントに参加し、一緒にゴールドクリエーションの道を歩み始めました。

非同期を初期化する4つの方法

1.スレッドの継承2.Runnableの実装
3.Callable
インターフェースの実装+Future(jdk1.5以降、戻り結果を取得して例外を処理できます)
4.スレッドプール[ExecutorService](実際の開発で使用)

モード1、2:メインスレッドはスレッドの動作結果を取得できません。
モード3:メインスレッドはスレッドの操作結果を取得できますが、サーバー内のスレッドリソースを制御するのに役立ちません。サーバーリソースの枯渇につながる可能性があります。
モード4:スレッドプールのパフォーマンスは安定しており、リソースは制御され、実行結果も取得でき、例外をキャッチできます。

スレッドプールの7つのパラメーター:

  1. corePoolSize:[5]コアスレッドの数[(allowCoreThreadTimeOutがリサイクルされない限り)常に存在します];スレッドプール、作成後に5スレッドの準備ができていますThread thread = new Thread();開始されていません。thread.start();は、タスクがスレッドプールに送信された後にのみ実行されます。
  2. maximumPoolSize:[200]スレッドの最大数;制御リソース
  3. keepAliveTime:生き続ける時間。現在のスレッド数がコア数よりも多い場合。アイドル状態のスレッドを解放します(maximumPoolSize-corePoolSize)。スレッドが指定されたkeepAliveTimeより長くアイドル状態である限り。
  4. unit:時間の単位。
  5. BlockingQueue workQueue:ブロックキュー。タスクが多い場合は、現在のタスクがキューに入れられます。アイドル状態のスレッドがある限り、キューに戻り、新しいタスクを実行して実行を続行します。new LinedBlockingDeque <>():デフォルトは整数の最大値であり、メモリ不足が発生します
  6. threadFactory:スレッド作成ファクトリ
  7. RejectedExecutionHandlerハンドラー:ポリシー列を拒否し、キューがいっぱいの場合は、対応する拒否ポリシーを実行します7.1 DiscardOldestPolicy:新しいタスク   が入った
      ときに実行されない古いタスクを破棄   し   ます7.4 DiscardPolicy:例外をスローせずに直接破棄します



作業順序:

  1. スレッドプールが作成され、コア数のコアスレッドの準備が整い、タスクを受け入れる準備が整います。
  2. コアがいっぱいになると、着信タスクはブロッキングキューに配置され、アイドル状態のコアはブロッキングキューに移動して、タスクを実行します。
  3. ブロッキングキューがいっぱいになると、実行のために新しいスレッドが直接開かれ、maximumはmaxで指定された数までしか開くことができません。
  4. maxがいっぱいになると、タスクはRejectedExecutionHandlerストラテジーで拒否されます。
  5. 最大実行が完了し、多くのアイドル時間があり、指定された時間keepAliveTimeの後、最大コアスレッドが解放されます

エグゼキュータ

  1. newCachedThreadPool()コアは0であり、すべてリサイクル可能です
  2. newFixedThreadPool()固定サイズcore=max;リサイクルできません
  3. 時限タスク用のnewScheduledThreadPllo()スレッドプール
  4. newSingleThreadExecutor()シングルスレッドスレッドプール、バックグラウンドはタスクを1つずつ実行します

1.非同期オブジェクトを作成します

CompletableFutureは4つの静的メソッドを提供します

//可以获取到返回值,可传入自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
//没有返回值,可传入自定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)
复制代码

テスト

public static ExecutorService service = Executors.newFixedThreadPool(10);
  //没有返回值
        CompletableFuture.runAsync(()->{
            System.out.println("异步任务成功完成了");
        },service);
        //空入参只有返回值
        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return "返回值";
        }, service);
复制代码

2.計算完了時のコールバック方式

//上一个任务完成和上一个任务用同一个线程
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
//交给线程池重新启动一个线程
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action);
//任务执行完成后(只能感知)
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
//感知异常同时修改返回值
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn);
复制代码

テストコード

 CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 10;
        }, service).whenComplete((res,excption)->{
            //虽然能得到异常消息但是不能修改返回结果
            System.out.println("异步任务成功完成了"+res+"或者异常:"+excption);
        }).exceptionally(throwable ->{
            //处理异常并可以数据修改返回值
            return 0;
       });
复制代码

3.ハンドルメソッド(例外が発生したときに処理して返す)

//和上一个任务使用同一个线程执行
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
//默认线程池开启线程执行
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn)
//指定自己的线程池开启线程执行
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)
复制代码

4.ハンドルテスト

       //方法执行完成后的处理不论成功还是失败
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 10;
        }, service).handle((res,thr)->{
            //未出现异常 当然这里可以不写 为了掩饰
           if(res!=null){
               return 0;
           }
           //出现异常
           if(thr!=null){
               return 1;
           }
           return 0;
        });
复制代码

5.スレッドのシリアル化方法(タスクBは、タスクAの実行結果の後でのみ実行できます)

//A-->B-->C 感知上一步结果并返回最后一次的结果
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn,Executor executor)

//B可以感知到A的返回值 
public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) 
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
                                                   Executor executor)
//A->完成后(有Async开启新的线程没有就是和A一个线程)感知不到上一步的执行结果                                                   
public CompletableFuture<Void> thenRun(Runnable action) 
public CompletableFuture<Void> thenRunAsync(Runnable action) 
public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor) 
复制代码

テスト

CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //任务A
            return 10;
        }, service).thenRunAsync(() -> {
            //感知不到 任务A的结果
        },service);
复制代码
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //任务A
            return 10;
        }, service).thenAcceptAsync((res) -> {
            //可以感知到任务A的结果,但是不能返回数据
            int i = res / 2;
        },service);
复制代码
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            //任务A
            return 10;
        }, service).thenApplyAsync((res) -> {
        //返回值以最后一次返回为准
            return 10 + res;
        }, service);
复制代码

6.2つのタスクの組み合わせ-両方を完了する必要があります

以下三种方式 两个任务都必须完成,才触发该任务
//组合两个future,获取两个future 任务的返回结果,并返回当前任务的返回值
public <U,V> CompletableFuture<V> thenCombine(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn)

public <U,V> CompletableFuture<V> thenCombineAsync(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn)

public <U,V> CompletableFuture<V> thenCombineAsync(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn, Executor executor) 

//组合两个future,获取两个future 任务的返回结果,然后处理任务,没有返回值。
public <U> CompletableFuture<Void> thenAcceptBoth(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action)

public <U> CompletableFuture<Void> thenAcceptBothAsync(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action)
        
public <U> CompletableFuture<Void> thenAcceptBothAsync(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action, Executor executor) 
        
//组合两个future ,不需要获取future的结果,只需要两个 future处理完成后处理该任务        
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,Runnable action) 

public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action) 
                                                     
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor)
复制代码

テスト

        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            //任务A
            System.out.println(Thread.currentThread().getId());
            System.out.println("任务一结束");
            return 10/2;
        }, service);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            //任务A
            System.out.println(Thread.currentThread().getId());
            System.out.println("任务二结束");
            return "future02";
        }, service);
        //不能感知到结果
        CompletableFuture<Void> future03void = future01.runAfterBothAsync(future02, () -> {
            System.out.println("任务三执行结束");
        }, service);
        //可以感知获取到前两个任务结果
        CompletableFuture<Void> future03No = future01.thenAcceptBothAsync(future02, (res1, res2) -> {
            System.out.println("任务三执行结束");
        }, service);
        CompletableFuture<String> future03 = future01.thenCombineAsync(future02, (res1, res2) -> {
            System.out.println("任务三执行结束");
            return res1 + "-" + res2;
        }, service);
复制代码

7.2つのタスクが1つずつ完了します

//两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值
public <U> CompletableFuture<U> applyToEither( CompletionStage<? extends T> other, Function<? super T, U> fn) 

public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn)
        
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T>other,Function<? super T, U> fn,Executor executor) 
//两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值
public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)

public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action)

public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action,Executor executor)
//两个任务有一个执行完成,不需要获取future的结果,处理任务 ,也没有返回值
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action)

public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action)
                                                       
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor)
复制代码

テスト

		 /**
         * 两个任务有一个完成就执行三
         *
         */
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            //任务A
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getId());
            System.out.println("任务一结束");

            return 10/2;
        }, service);
        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            //任务A
            System.out.println(Thread.currentThread().getId());

            System.out.println("任务二结束");
            return "future02";
        }, service);
        //不感知结果,自己也没有返回值
        future01.runAfterEitherAsync(future02,()->{
            System.out.println("任务三执行结束");
        },service);
        //感知到结果,自己没有返回值
        future01.acceptEitherAsync(future02,(res)->{
            //感知到线程已经处理完成的结果
            System.out.println("任务三执行结束"+res);
        },service);
        //感知到结果并返回自己的返回值
        CompletableFuture<String> stringCompletableFuture = future01.applyToEitherAsync(future02, res -> {
            return "任务三结果" + res;
        }, service);
复制代码

8.マルチタスクの組み合わせ

//等待所有任务完成
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
//只要有一个任务完成
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
复制代码

テスト

CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            //任务A
            System.out.println(Thread.currentThread().getId());
            System.out.println("任务一结束");

            return 10/2;
        }, service);
        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            //任务A
            System.out.println(Thread.currentThread().getId());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务二结束");
            return "future02";
        }, service);
        //此方法是阻塞式等待不建议在这使用
        //future01.get();
        //future02.get();
        
		//等待所有任务完成不会阻塞
        CompletableFuture<Void> allOf= CompletableFuture.allOf(future01, future02);
        //等待所有的都完成(两个任务同时执行)
        allOf.get();
        log.info("end");
        System.out.println(future02.get()+""+future01.get());
        //只有一个完成
        CompletableFuture<Object> anyOf= CompletableFuture.anyOf(future01, future02);
        anyOf.get();
        System.out.println(anyOf.get());

复制代码

おすすめ

転載: juejin.im/post/7079649904724803591