CompletableFuture 使用

简介: CompletableFuture 使用

美团外面,滴滴打车很多场景都会使用到。

当我们在软件下单的时候, 付款之后,系统马上就会提示我们下单成功,而

而这个背后我们来分析下,有很多地方有数据处理的工作。保存订单到数据库、通知商家接单、通知骑手取货。整个流程的体验是非常快的,这其中肯定也是异步化的。

我们后端的开发也是一样的,我们不能因为某一次的延迟而让后面所以的请求进行等待。

异步技术:

Java 5 Future接口

使用Future获得异步执行结果时,要么调用阻塞方法get(),要么轮询看isDone()是否为true,这两种方法都不是很好,因为主线程也会被迫等待。

public class TestK {
   public static int helloZero() throws ExecutionException, InterruptedException {
       ExecutorService executorService = Executors.newFixedThreadPool(2);
       Future<Integer> result = executorService.submit(()->{
           TimeUnit.SECONDS.sleep(5);
           return 100;
       });
       System.out.println(result.get());
       return 1;
   }
    public static int helloOne() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<Integer>  result = executorService.submit(()->{
           return 300;
        });
        while (!result.isDone()) {
            TimeUnit.MILLISECONDS.sleep(100);
        }
        System.out.println(result.get());
        return 3;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestK.helloZero();
        TestK.helloOne();
    }
}

输出结果

通过主线程输出语句,我们看到必须要等待线程池执行完成才会执行main线程。这样的话非常浪费cpu资源的,为什么不能用类似观察者或者监听的模式,当任务完成之后,我就能收到结果。这就要涉及到回调函数。


1、同步阻塞调用

即串行调用,响应时间为所有服务的响应时间总和;

2、半异步(异步Future)

线程池,异步Future

使用场景:并发请求多服务。总耗时为最长响应时间;提升总响应时间,但是阻塞主请求线程,高并发时依然会造成线程数过多,CPU上下文切换;

3、全异步(Callback)

Callback方式调用,使用场景:不考虑回调时间且只能对结果做简单处理,如果依赖服务是两个或两个以上服务,则不能合并两个服务的处理结果;不阻塞主请求线程,但使用场景有限。

4、异步回调

异步回调链式编排(JDK8 CompletableFuture),使用场景:其实不是异步调用方式,只是对依赖多服务的Callback调用结果处理做结果编排,来弥补Callback的不足,从而实现全异步链式调用。

CompletableFuture类介绍:

* @author Doug Lea
  * @since 1.8
 */
public class CompletableFuture<T> implements Future<T>,CompletionStage<T> {}

列子1:那个线程跑的快用哪个acceptEither函数

public class TestU {
    public static CompletableFuture<Integer> m1() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1111;
        });
    }
    private static CompletableFuture<Integer> m2() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 2222;
        });
    }
    /***
      * acceptEither函数
      * 那个线程跑的快用哪个
      * @param args
      * @throws Exception
      */
    public static void main(String[] args) throws Exception {
        m1().acceptEither(m2(), t -> {
            System.out.println("t = " + t);
        }).get();
    }
}

输出结果为


列子2:两个任何结果合并:thenCombine函数

public class TestJ {
    public static void main(String[] args) {
        try {
            String k = CompletableFuture.supplyAsync(() -> 1).thenCombine(CompletableFuture.supplyAsync(() -> "2"), (a, b) -> {
                System.out.println("a = " + a);
                System.out.println("b = " + b);
                return a + b;
            }).get();
            System.out.println("k = " + k);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出结果为

场景:

supplyAsync  thenApplyAsync

ABC  C必须等到A条件完成了才完成,而B不需要等待,这种如何处理?

场景介绍:

1、获取sku的基本信息 1S

2、获取sku的图片信息 2s

3、获取sku的促销信息 3s

4、规格信息spu

5、............

public class TestN {
    public static void main(String[]args) throws Exception {
        // 第一个任务:商品id
        CompletableFuture<String> cfQuery = CompletableFuture.supplyAsync(()->{
           return query("iphone12");
        });
        // // query成功后继续执行下一个任务:
        CompletableFuture<String> cfFetch = cfQuery.thenApplyAsync((code)->{
            return comment(code);
        });
        cfFetch.thenAccept((result)->{
            System.out.println(result);
        });
        // // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(2000);
    }
    private static String query(String name) {
        try{
            Thread.sleep(100);
        }catch (Exception e){
            e.printStackTrace();
        }
        int random = new Random().nextInt(100);
        System.out.println("random = "+random);
        return random <= 20 ? "20210709":"0000";
    }
    private static String comment(String code){
        if(code.equals("0000")){
            return "没有任何评论";
        }
        return "苹果没有小米好";
    }

输出结果为

目录
相关文章
cron-utils获取下几次执行时间
cron-utils获取下几次执行时间
415 0
|
负载均衡 监控 Java
异步编程 - 14 异步、分布式、基于消息驱动的框架 Akka
异步编程 - 14 异步、分布式、基于消息驱动的框架 Akka
425 0
|
7月前
|
存储 并行计算 Java
CompletableFuture原理及应用场景详解
CompletableFuture是Java 8引入的异步编程工具,用于优化多任务并行处理。相比传统Future,它支持可组合操作(如thenApply、thenCombine),避免回调地狱,同时降低依赖间的阻塞。其核心通过result存储结果,stack管理依赖动作,基于观察者模式实现回调通知。使用中需注意:异步方法建议显式传入线程池以隔离资源;异常信息需通过get()或exceptionally捕获。适用于复杂业务场景,如APP页面加载涉及多服务API调用时,可显著提升性能与代码可读性。
574 4
|
5月前
|
存储 JSON 数据格式
什么情况,一夜之间冲上热搜,狂揽29.6k星,再见吧SQLite!这个嵌入式分析引擎实在太香了
DuckDB是一款嵌入式OLAP数据库,专为高效分析型查询设计,被誉为“分析型SQLite”。它采用列式存储和向量化查询引擎,显著提升分析任务性能。无需独立服务器,支持Python、R、Java等语言,安装简单,5分钟即可上手。DuckDB可直接查询CSV、JSON、Parquet文件,支持Pandas零拷贝交互,优化SQL语法简化复杂查询。适用于探索性数据分析、数据湖ETL流水线及边缘设备实时分析等场景,是数据科学家和开发者的理想工具。项目地址:https://github.com/duckdb/duckdb
305 4
|
12月前
|
存储 安全 前端开发
Elasticsearch 使用误区之六——富文本内容写入前不清洗
【10月更文挑战第6天】在大数据和全文搜索领域,Elasticsearch(简称ES)凭借其强大的搜索和分析能力,成为众多企业和开发者的首选工具。然而,在实际应用中,很多开发者在使用ES时存在一些误区,其中之一便是富文本内容写入前不进行清洗。本文将深入探讨这一误区,并提供一些实用的清洗策略和最佳实践。
199 3
|
10月前
|
机器学习/深度学习 并行计算 测试技术
每天五分钟深度学习:解决for循环效率慢的关键在于向量化
向量化是提升计算效率的重要技术,尤其是在处理大规模数据和进行复杂运算时。通过将for循环转换为向量或矩阵运算,向量化能够充分利用底层高效库和现代CPU的并行计算能力,从而大幅提高运算速度。在深度学习中,向量化是实现高效神经网络训练和预测的关键。
265 23
|
10月前
|
存储 JSON 自然语言处理
es索引文档过程
Elasticsearch 索引文档流程:先通过 REST API 或客户端创建索引,定义文档结构的映射;接着索引 JSON 格式的文档,Elasticsearch 解析、索引并存储;最后,文档以倒排索引形式存储,支持高效全文搜索。
151 5
|
消息中间件 缓存 NoSQL
如何实现消费幂等 ?
这篇文章,我们聊聊消息队列中非常重要的最佳实践之一:**消费幂等**。
如何实现消费幂等 ?
|
11月前
|
JSON 测试技术 API
ES API,使用Kibana的开发工具用例说明
ES API,使用Kibana的开发工具用例说明
108 0
|
Java 开发者 Spring
CompletableFuture 使用总结
CompletableFuture 使用总结
348 1