Administrator
发布于 2024-07-31 / 20 阅读
0
0

CompletableFurture实战1

CompletableFurture实战1.md

背景:

由于需要多处查询,以此查询的话比较耗时,当然也可以用定时同步es或者某个中间件然后再查询,本次采用的多线程查询,利用的是CompletableFuture

当然也可以lietflow 只不过比较简单就没有采用框架,顺便也了解下这个怎么用

目标

Title: 整合数据
A->B: 获取数据库数据(同步)
B-->C: 根据数据id获取c端数据(异步)
B-->D: 根据数据id获取d端数据(异步)
B-->E: 根据数据id获取e端数据(异步)

也就是 a发起获取b中的id,然后分别从c 、d 、e中拉取数据,然后再汇总

构思

  1. 首先想到的是 supplyAsync是同步返回结果的,runAsync是没有返回结果的

    supplyAsync(() -> {
               return "获取b中的id";
           })
  2. 接受前面的返回参数为:thenAccept 和 thenAcceptAsync (当然也有很多,本次讨论这两个)这两个方法:一个是在当前线程中执行,另外一个是异步执行。我们选择的是thenAcceptAsync ,毕竟要速度嘛。

  3. 我们需要分别获取c,d,e中的数据,所以可以利用 CompletableFuture中 allof方法,对应有个anyof 就是任意一个返回即可,但是我们需要全部返回

    CompletableFuture<Void> voidCompletableFuture = supplyAsync(() -> {
               System.out.println("执行获取b中的id"); return "获取b中的id";
           }).thenAcceptAsync(bb -> {
    
                   allOf(runAsync(() -> {
                       try {
                           //获取c
                           Thread.sleep(10000);
                       }
                       catch (InterruptedException e) {
                           throw new RuntimeException(e);
                       } System.out.println(bb + " " + Thread.currentThread().getName());
                   }, threadPoolTaskExecutor), runAsync(() -> {
                       try {
                           //获取d
                           Thread.sleep(20000);
                       }
                       catch (InterruptedException e) {
                           throw new RuntimeException(e);
                       } System.out.println(bb + " " + Thread.currentThread().getName());
                   }, threadPoolTaskExecutor), runAsync(() -> {
                       try {
                           //获取e
                           Thread.sleep(20000);
                       }
                       catch (InterruptedException e) {
                           throw new RuntimeException(e);
                       } System.out.println(bb + " " + Thread.currentThread().getName());
                   }, threadPoolTaskExecutor)) ;
    
           });
           System.out.println("执行状态:"+voidCompletableFuture.isDone());
           while (!voidCompletableFuture.isDone()) {
               try {
                   //获取e
                   Thread.sleep(1000);
                   System.out.println("等待执行完成");
               }
               catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
           System.out.println("执行状态:"+voidCompletableFuture.isDone());
           System.out.println("主线程执行位置");        }, threadPoolTaskExecutor)));
执行获取b中的id
执行状态:false
等待执行完成
执行状态:true
主线程执行位置

这时候发现,并不是我想要的,

    1. 将   thenAcceptAsy改成 同步的thenAccep可以吗?如下所示不行

执行获取b中的id 执行状态:true 执行状态:true 主线程执行位置

    2. 所以我们将注意放到thenAcceptAsync方法中,其实就是带Async就想new Thread一样,不带就在当前Thread里面执行,但是我们内部用的CompletableFurture.allOf()方法,相当于在方法体内创建一个几个线程来执行,没有同步只等他们执行完。我们在allof()方法后面增加.get()方法,

执行获取b中的id 执行状态:false 等待执行完成 .... 获取b中的id threadPoolTaskExecutor-1 等待执行完成 .... 获取b中的id threadPoolTaskExecutor-2 获取b中的id threadPoolTaskExecutor-3 等待执行完成 执行状态:true 主线程执行位置

    3. 综上所述,在CompletableFurture中提供的方法返回的furture对象,如果在内部开启了线程除非同步等待内部执行完成如.get()方法或者.join()方法,否者该对象完成是不包含内部线程池的内容,相当于把任务丢给别了就拉到了, 想必如果只是几个thread在一起掺和还可以分得清,但是换一种模式就不太好理解了


评论