[Business Functions Chapter 92] Microservices-springcloud-multi-threading-asynchronous processing-asynchronous orchestration-CompletableFutrue

三、CompletableFutrue

A product details page

  • Display basic information of SKU for 0.5s
  • Display SKU picture information 0.6s
  • Display SKU sales information 1s
  • SPU sales attributes 1s
  • Display specifications and parameters for 1.5s
  • spu details information 1s

1. Introduction to ComplatableFuture

  Future is a class added in Java 5 to describe the result of an asynchronous calculation. You can use isDone methods to check whether the calculation is completed, or use getmethods to block the calling thread until the calculation is completed and return results. You can also use cancelmethods to stop the execution of the task.

  Although Future the related usage methods provide the ability to execute tasks asynchronously, it is very inconvenient to obtain the results. The results of the tasks can only be obtained through blocking or polling. The blocking method obviously goes against the original intention of our asynchronous programming. The polling method consumes unnecessary CPU resources and cannot obtain the calculation results in time. Why can't we use the observer design pattern to notify the listener in time when the calculation results are completed? Woolen cloth?

  Many languages, such as Node.js, use callbacks to implement asynchronous programming. Some Java frameworks, such as Netty, extend Java Futureinterfaces and provide addListenermultiple extension methods; Google guava also provides a general extended Future; Scala also provides an easy-to-use and powerful Future/Promise asynchronous programming mode. .

  As an orthodox Java class library, should we do something to enhance the functions of our own library?

  In Java 8, a new class containing about 50 methods has been added: CompletableFuture, which provides very powerful Future extension functions, can help us simplify the complexity of asynchronous programming, and provides functional programming capabilities through callbacks. The calculation results are processed in a way, and methods for converting and combining CompletableFuture are provided.

  The CompletableFuture class implements the Future interface, so you can still obtain results through method blocking or polling as before get, but this method is not recommended.

  CompletableFuture and FutureTask both belong to the implementation class of the Future interface, and both can obtain the execution results of the thread.

image.png

2. Create an asynchronous object

CompletableFuture provides four static methods to create an asynchronous operation.

static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

Methods are divided into two categories:

  • runAsync returns no result
  • supplyAsync has return results
    private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5
            ,50
            ,10
            , TimeUnit.SECONDS
            ,new LinkedBlockingQueue<>(100)
            , Executors.defaultThreadFactory()
            ,new ThreadPoolExecutor.AbortPolicy()
    );

    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    

        System.out.println("main -- 线程开始了...");
        // 获取CompletableFuture对象
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
    
    
            System.out.println("线程开始了...");
            int i = 100/50;
            System.out.println("线程结束了...");
        },executor);
        System.out.println("main -- 线程结束了...");

        System.out.println("------------");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println("线程开始了...");
            int i = 100 / 50;
            System.out.println("线程结束了...");
            return i;
        }, executor);
        System.out.println("获取的线程的返回结果是:" + future.get() );
    }

3.whenXXX and handle methods

  When the calculation result of CompletableFuture is completed or an exception is thrown, a specific Action can be executed. Mainly the following methods:

public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action);
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action);
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);

public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn);

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) ;

Description of related methods:

  • whenComplete can obtain the return value of the asynchronous task and the exception information thrown, but it cannot modify the return result.
  • execptionlly is a method that will be triggered when an asynchronous task throws an exception. If no exception is thrown, the method will not be executed.
  • handle can obtain the return value and thrown exception information of the asynchronous task, and can display the returned result.
/**
 * CompletableFuture的介绍
 */
public class CompletableFutureDemo2 {
    
    

    private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5
            ,50
            ,10
            , TimeUnit.SECONDS
            ,new LinkedBlockingQueue<>(100)
            , Executors.defaultThreadFactory()
            ,new ThreadPoolExecutor.AbortPolicy()
    );

    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println("线程开始了...");
            int i = 100 / 5;
            System.out.println("线程结束了...");
            return i;
        }, executor).handle((res,exec)->{
    
    
            System.out.println("res = " + res + ":exec="+exec);
            return res * 10;
        });
        // 可以处理异步任务之后的操作
        System.out.println("获取的线程的返回结果是:" + future.get() );
    }

 /*   public static void main(String[] args) throws ExecutionException, InterruptedException {

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程开始了...");
            int i = 100 / 5;
            System.out.println("线程结束了...");
            return i;
        }, executor).whenCompleteAsync((res,exec)->{
            System.out.println("res = " + res);
            System.out.println("exec = " + exec);
        }).exceptionally((res)->{ // 在异步任务显示的抛出了异常后才会触发的方法
            System.out.println("res = " + res);
            return 10;
        });
        // 可以处理异步任务之后的操作
        System.out.println("获取的线程的返回结果是:" + future.get() );
    }*/

/*    public static void main(String[] args) throws ExecutionException, InterruptedException {

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程开始了...");
            int i = 100 / 0;
            System.out.println("线程结束了...");
            return i;
        }, executor).whenCompleteAsync((res,exec)->{
            System.out.println("res = " + res);
            System.out.println("exec = " + exec);
        });
        // 可以处理异步任务之后的操作
        System.out.println("获取的线程的返回结果是:" + future.get() );
    }*/
}

4. Thread serial method

thenApply method: When a thread depends on another thread, obtain the result returned by the previous task and return the return value of the current task.

thenAccept method: consume processing results. Receive the processing results of the task and consume the processing without returning any results.

thenRun method: As long as the above task is completed, thenRun will be executed. Only after the task is processed, the subsequent operations of thenRun will be executed.

With Async, execution is asynchronous by default. The so-called asynchronous here refers to not executing in the current thread.

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)

public CompletionStage<Void> thenAccept(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor);

public CompletionStage<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);
/**
 * CompletableFuture的介绍
 */
public class CompletableFutureDemo3 {
    
    

    private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5
            ,50
            ,10
            , TimeUnit.SECONDS
            ,new LinkedBlockingQueue<>(100)
            , Executors.defaultThreadFactory()
            ,new ThreadPoolExecutor.AbortPolicy()
    );

    /**
     * 线程串行的方法
     * thenRun:在前一个线程执行完成后,开始执行,不会获取前一个线程的返回结果,也不会返回信息
     * thenAccept:在前一个线程执行完成后,开始执行,获取前一个线程的返回结果,不会返回信息
     * thenApply: 在前一个线程执行完成后。开始执行,获取前一个线程的返回结果,同时也会返回信息
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println("线程开始了..." + Thread.currentThread().getName());
            int i = 100 / 5;
            System.out.println("线程结束了..." + Thread.currentThread().getName());
            return i;
        }, executor).thenApply(res -> {
    
    
            System.out.println("res = " + res);
            return res * 100;
        });
        // 可以处理异步任务之后的操作
        System.out.println("获取的线程的返回结果是:" + future.get() );
    }
    /*public static void main(String[] args) throws ExecutionException, InterruptedException {

        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程开始了..." + Thread.currentThread().getName());
            int i = 100 / 5;
            System.out.println("线程结束了..." + Thread.currentThread().getName());
            return i;
        }, executor).thenAcceptAsync(res -> {
            System.out.println(res + ":" + Thread.currentThread().getName());
        }, executor);
        // 可以处理异步任务之后的操作
        //System.out.println("获取的线程的返回结果是:" + future.get() );
    }*/
    /*public static void main(String[] args) throws ExecutionException, InterruptedException {

        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程开始了..."+Thread.currentThread().getName());
            int i = 100 / 5;
            System.out.println("线程结束了..."+Thread.currentThread().getName());
            return i;
        }, executor).thenRunAsync(() -> {
            System.out.println("线程开始了..."+Thread.currentThread().getName());
            int i = 100 / 5;
            System.out.println("线程结束了..."+Thread.currentThread().getName());
        }, executor);
        // 可以处理异步任务之后的操作
        //System.out.println("获取的线程的返回结果是:" + future.get() );
    }*/

}

5. Complete both

  The related methods introduced above are all executed serially. Next, let’s take a look at several methods that need to wait for the completion of the two tasks before they are triggered.

  • thenCombine: You can get the return results of the previous two threads, and also have the return results itself.
  • thenAcceptBoth: You can get the return results of the previous two threads, but there is no return result itself.
  • runAfterBoth: The return results of the previous two threads cannot be obtained, and there is no return result itself.
/**
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    

        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println("任务1 线程开始了..." + Thread.currentThread().getName());
            int i = 100 / 5;
            System.out.println("任务1 线程结束了..." + Thread.currentThread().getName());
            return i;
        }, executor);
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println("任务2 线程开始了..." + Thread.currentThread().getName());
            int i = 100 /10;
            System.out.println("任务2 线程结束了..." + Thread.currentThread().getName());
            return i;
        }, executor);

        // runAfterBothAsync 不能获取前面两个线程的返回结果,本身也没有返回结果
        CompletableFuture<Void> voidCompletableFuture = future1.runAfterBothAsync(future2, () -> {
    
    
            System.out.println("任务3执行了");
        },executor);

        // thenAcceptBothAsync 可以获取前面两个线程的返回结果,本身没有返回结果
        CompletableFuture<Void> voidCompletableFuture1 = future1.thenAcceptBothAsync(future2, (f1, f2) -> {
    
    
            System.out.println("f1 = " + f1);
            System.out.println("f2 = " + f2);
        }, executor);

        // thenCombineAsync: 既可以获取前面两个线程的返回结果,同时也会返回结果给阻塞的线程
        CompletableFuture<String> stringCompletableFuture = future1.thenCombineAsync(future2, (f1, f2) -> {
    
    
            return f1 + ":" + f2;
        }, executor);

        // 可以处理异步任务之后的操作
        System.out.println("获取的线程的返回结果是:" + stringCompletableFuture.get() );
    }

6. Complete two tasks and complete one

  Based on the above five tasks, let’s take a look at the situation where task 3 will be triggered as long as one of the two tasks is completed.

  • runAfterEither: cannot obtain the return result of the completed thread, and does not return the result itself.
  • acceptEither: can obtain the return result of the thread, but does not return the result itself.
  • applyToEither: can not only obtain the return result of the thread, but also return the result itself
/**
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    

        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println("任务1 线程开始了..." + Thread.currentThread().getName());
            int i = 100 / 5;
            System.out.println("任务1 线程结束了..." + Thread.currentThread().getName());
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println("任务2 线程开始了..." + Thread.currentThread().getName());
            int i = 100 /10;
            try {
    
    
                Thread.sleep(5000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("任务2 线程结束了..." + Thread.currentThread().getName());
            return i+"";
        }, executor);
        // runAfterEitherAsync 不能获取前面完成的线程的返回结果,自身也没有返回结果
        future1.runAfterEitherAsync(future2,()->{
    
    
            System.out.println("任务3执行了....");
        },executor);

        // acceptEitherAsync 可以获取前面完成的线程的返回结果  自身没有返回结果
        future1.acceptEitherAsync(future2,(res)->{
    
    
            System.out.println("res = " + res);
        },executor);

        // applyToEitherAsync 既可以获取完成任务的线程的返回结果  自身也有返回结果
        CompletableFuture<String> stringCompletableFuture = future1.applyToEitherAsync(future2, (res) -> {
    
    
            System.out.println("res = " + res);
            return res + "-->OK";
        }, executor);
        // 可以处理异步任务之后的操作
        System.out.println("获取的线程的返回结果是:" + stringCompletableFuture.get() );
    }

7.Multi-tasking combination

allOf: wait for all tasks to complete

anyOf: As long as one task is completed

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);

public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);
/**
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1 线程开始了..." + Thread.currentThread().getName());
            int i = 100 / 5;
            System.out.println("任务1 线程结束了..." + Thread.currentThread().getName());
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2 线程开始了..." + Thread.currentThread().getName());
            int i = 100 /10;
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务2 线程结束了..." + Thread.currentThread().getName());
            return i+"";
        }, executor);

        CompletableFuture<Object> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务3 线程开始了..." + Thread.currentThread().getName());
            int i = 100 /10;
            System.out.println("任务3 线程结束了..." + Thread.currentThread().getName());
            return i+"";
        }, executor);

        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future1, future2, future3);
        anyOf.get();
        System.out.println("主任务执行完成..." + anyOf.get());

        CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2, future3);
        allOf.get();// 阻塞在这个位置,等待所有的任务执行完成
        System.out.println("主任务执行完成..." + future1.get() + " :" + future2.get() + " :" + future3.get());
    }

Guess you like

Origin blog.csdn.net/studyday1/article/details/132610270