Java异步编排 2021-09-11

Java 异步并发与池化技术

异步编排

  • Java 异步并发与池化技术
  • 一、什么是异步调用
  • 二 Future接口
  • 三、异步开启
  • 四、CompletableFuture接口实现异步编排
    • 4.1串行关系执行
      • 4.1.1 串行关系方法
      • 4.1.2 代码使用示例
    • 4.2聚合关系 AND
    • 4.3聚合关系 OR
    • 4.4 异常处理


一、什么是异步调用

异步调用实现一个不需要被等待的方法的返回值;让调用者(主线程)继续执行(异步执行);在 java 中,简单的讲就是开启另一个线程完成程序计算(子线程),使得调用者(主线程)继续执行,不需要等待计算的结果,但是调用者任然需要获取线程的计算结果(不需要同步阻塞等待)。调用后无需等待,任务交给子线程,主线程继续执行。

二 Future接口

Future 也是一个异步计算结果返回接口,目的获取返回值结果。但是 future 在获取返回值结果的时候,方法必须同步阻塞等待返回值结果。

  • Get : 获取结果(等待,阻塞)
  • Get(timeout) : 获取结果,指定等待时间
  • Cancel : 取消当前任务
  • isDone : 判断任务是否已经完成 (轮询)

结论: futrure 对于结果获取不是很方便,只能通过同步阻塞的方式获取结果,或者是轮询的方式获取到结果;阻塞的方式获取返回值结果与异步的思想想违背,轮询方式又很占用 cpu 资源,也不能及时得到我们结果。

三、异步开启

CompletableFuture 提供了 4 个静态的方法,来创建一个异步操作(异步开启: 从这 4 个静态的方法开发即可)

  • runAsync: 没有返回值的方法,不关注返回值
public static CompletableFuture<Void> runAsync(Runnable runnable); 
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor); 
  • supplyAsync : 有返回值,关注返回值的。
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)

代码示例:

@Slf4j
public class AsyncFutureDemo {
    public static ThreadPoolExecutor executorPool = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
            9, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3),
            Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*异步编排无返回值*/
        /*RunAsync : 不传线程池,则默认使用的线程池 ForkJoinPool.commonPool*/
        /*RunAsync : 这里使用自定义的线程池*/
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            // 业务代码执行
            int j = 100 / 3;
            log.info("子线程{},线程执行结果{}",Thread.currentThread().getName(),j);
        },executorPool);
        /*调用异步任务*/
        future.get();
        log.info("主线程end");
    }
}

四、CompletableFuture接口实现异步编排

CompletableFuture 可以帮助我们简化异步编程复杂性,提供了函数式编程的能力,可以通 过回调函数的方式处理计算结果。

public class CompletableFuture<T> implements Future<T>, CompletionStage<T>

CompletableFuture 具有Future的特性,还实现了CompletionStage接口,具备CompletionStage 接口的特性: 串行执行,并行执行,聚合(AND 聚合,OR 聚合)

4.1串行关系执行

串行关系执行: then – 然后,也就是表示下一步,所以通常是一个串行的关系体现,then 后面的单词(比如 run/apply/accept)就是函数是接口中抽象方法名称; 串行关系执行: 利用上一步的执行结果,去进行下一步任务执行,任务执行具有先后顺序, 因此把这种操作叫做串行关系。Async 表示异步。

4.1.1 串行关系方法

查看Function 接收参数查看参数的情况 void accept(T t, U u);

  • thenRun 没有返回值,只和上一步有顺序关系,不关心上一步执行结果。
  • thenApply 具有返回值,上一步直接的结果当成传参的传 递给 thenApply #T 就是参数类型,U 就是返回值类型。
  • thenAccept 没有返回值,跟上一步的结果有关系,上一步结果会被消费。
  • thenCompose 有返回值,依赖于上一步的返回结果,上一步的结果作为参数传递,允许对两个CompletionStage流水线进行操作,第一个操作完成时,将第一个操作结果传递给第二个CompletionStage。
public CompletionStage<Void> thenRun(Runnable action); 
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);

public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn); 
public <U> CompletionStage<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 <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn); 
public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn); 
public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor);

4.1.2 代码使用示例

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*supplyAsync有返回值*/
        /* thenRun 没有返回值,只和上一步有顺序关系,不关心上一步执行结果。 */
        /*最终无返回值*/
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            // 业务代码执行
            int j = 100 / 3;
            log.info("子线程{},线程执行结果{}",Thread.currentThread().getName(),j);
            return j;
        }).thenRun(()->{
            log.info("thenRun{}运行...",Thread.currentThread().getName());
        });
        /*调用异步任务*/
        future.get();
        log.info("主线程end");
    }

thenCompose 的使用示例

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Long> thenCompose = CompletableFuture.supplyAsync(() -> {
            int j = 100 / 3;
            log.info("子线程{},线程执行结果{}", Thread.currentThread().getName(), j);
            return j;
        }).thenCompose(new Function<Integer, CompletionStage<Long>>() {
            @Override
            public CompletionStage<Long> apply(Integer u) {
                // 第二次执行
                CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
                    log.info("子线程开始,参数{}",u);
                    Long res = Long.valueOf(u * 5);
                    return res;
                });
                return future;
            }
        });
        Long aLong = thenCompose.get();
        log.info("主线程end,结果{}",aLong);
    }

4.2聚合关系 AND

thenCombine、thenAcceptBoth、runAfterBoth 都是要求两者都执行完毕,也就是 and 且的关系。

    // thenCombine: 把2 个阶段的 CompletionStage 都执行完毕后,把结果一块交给 thenAcceptBoth 进行执行,有返回值
    public <U,V> CompletionStage<V> thenCombine (CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn);
    // thenAcceptBoth: 当2个阶段的 CompletionStage 都执行完毕后,把结果一块交给 thenAcceptBoth 进行执行,没有返回值
    public <U> CompletionStage<Void> thenAcceptBoth (CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action);
    // runAfterBoth: 当2个阶段的 CompletionStage 都执行完毕后,才会执行下一个操作
    public CompletionStage<Void> runAfterBoth(CompletionStage<?> other, Runnable action);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            int j = 100 / 3;
            log.info("子线程{},线程执行结果{}", Thread.currentThread().getName(), j);
            return j;
        });
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
            int j = 100 / 4;
            log.info("子线程{},线程执行结果{}", Thread.currentThread().getName(), j);
            return j;
        });
        CompletableFuture<Long> thenCombine = f1.thenCombine(f2, (u, t) -> {
            /*u t 分别是两个阶段的结果*/
            Long res = Long.valueOf(u + t);
            return res;
        });
        Long aLong = thenCombine.get();
        log.info("主线程end,结果{}", aLong);
    }

4.3聚合关系 OR

关键词Either

	// 两个阶段,将计算结果最快的结果作为下一步处理的消费,有返回值
    public <U> CompletionStage<U> applyToEitherAsync (CompletionStage<? extends T> other, Function<? super T, U> fn);
    // 两个阶段,将计算结果最快的结果作为下一步处理的消费,无返回值
    public CompletionStage<Void> acceptEither (CompletionStage<? extends T> other, Consumer<? super T> action);
    //两个阶段,其中一个执行完后,执行无参数传递,无返回值
    public CompletionStage<Void> runAfterEitherAsync (CompletionStage<?> other, Runnable action);
@Slf4j
public class AsyncFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            int j = 100 / 3;
            log.info("子线程{},线程执行结果{}", Thread.currentThread().getName(), j);
            return j;
        });
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
            int j = 100 / 4;
            log.info("子线程{},线程执行结果{}", Thread.currentThread().getName(), j);
            return j;
        });
        CompletableFuture<Long> thenCombine = f1.applyToEither(f2, (t) -> {
            /*u t 分别是两个阶段的结果*/
            Long res = (long) t;
            return res;
        });
        Long aLong = thenCombine.get();
        log.info("主线程end,结果{}", aLong);
    }

4.4 异常处理

  • exceptionally 出现异常时,进入
  • whenComplete (t 上一步结果,u 异常类)上一步结束时进行, 无返回值。
  • handle 类似finally , 对上一步执行结果进行处理,还可以处理异常任务。有返回值。
    public CompletionStage<T> exceptionally(Function<Throwable, ? extends T> fn);
    public CompletionStage<T> whenComplete (BiConsumer<? super T, ? super Throwable> action);
    public <U> CompletionStage<U> handle (BiFunction<? super T, Throwable, ? extends U> fn);
@Slf4j
public class AsyncFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            int j = 100 / 4;
            log.info("子线程{},线程执行结果{}", Thread.currentThread().getName(), j);
            return j;
        }).exceptionally(throwable -> {
                    log.error("执行错误{}", throwable.getMessage());
                    return null;
                }
        );
        Integer aLong = f1.get();
        log.info("主线程end,结果{}", aLong);
    }

你可能感兴趣的:(Java,组件使用,java)