异步编程CompletableFuture

多线程优化性能,串行操作并行化

串行操作

// 以下2个都是耗时操作
doBizA();
doBizB();

修改变为并行化

new Thread(() -> doBizA()).start();
new Thread(() -> doBizB()).start();

异步化,是并行方案的基础,利用多线程优化性能。性能优化是大厂的核心需求
jdk1.8提供了CompletableFuture 来支持异步编程
CompletableFuture工具类还是很复杂的,需要做好心理准备

1.CompletableFuture实现烧水泡茶


任务3需要等待任务1和任务2都完成才能开始
范例

public static void tea(){
        CompletableFuture<Void> f1 = CompletableFuture.runAsync(() -> {
            System.out.println("T1:洗水壶...");
            sleep(1);
            System.out.println("T1:烧开水...");
            sleep(15);
        });

        CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("T2:洗茶壶...");
            sleep(1);
            System.out.println("T2:洗茶杯...");
            sleep(2);
            System.out.println("T2:拿茶叶...");
            sleep(1);
            return "龙井";
        });

        CompletableFuture<String> f3 =  f1.thenCombine(f2,(__, tea) -> {
            System.out.println("T1:拿到茶叶:" + tea);
            System.out.println("T1:泡茶...");
            return "tea:" + tea;
        });

        System.out.println(f3.join());
    }

核心4个静态方法

runAsync(Runnable runnable)   runnable接口的run方法没有返回值
supplyAsync(Supplier<U> supplier) Supplier接口的get方法有返回值

这2个方法,有重载方法,重载方法,支持传入自定义的线程池对象,默认不传使用的是jdk带的ForkJoinPool线程池,默认线程数是cpu核数的2倍
强烈建议,不同的业务类型创建不同的线程池,不要随便使用ForkJoinPool线程池,避免互相干扰

注意:
2个关注点
异步操作什么时候结束
如何获取异步操作的执行结果
都可以通过future接口get来解决

2.理解CompletionStage接口

1.串行关系

CompletableFuture f0 = CompletableFuture.supplyAsync( () -> "Hello World") //① 
.thenApply(s -> s + " QQ") //② 
.thenApply(String::toUpperCase);//③
System.out.println(f0.join());//输出结果HELLO WORLD QQ

2.AND汇聚关系

// 等f1,f2都执行完,f3开始执行
CompletableFuture<String> f3 =  f1.thenCombine(f2,(__, tea) -> {
System.out.println("T1:拿到茶叶:" + tea);
System.out.println("T1:泡茶...");
return "tea:" + tea;
});
posted @ 2021-02-07 15:55  SpecialSpeculator  阅读(108)  评论(0编辑  收藏  举报