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 "苹果没有小米好";
    }

输出结果为

目录
相关文章
|
4月前
|
缓存 Java Maven
CompletableFuture
【7月更文挑战第29天】
45 4
|
4月前
|
Java 开发者 Spring
CompletableFuture 使用总结
CompletableFuture 使用总结
113 1
|
3月前
CompletableFuture 打桌球的应用
CompletableFuture 打桌球的应用
17 0
|
3月前
|
Java 测试技术
CompletableFuture 使用
CompletableFuture 使用
41 0
|
6月前
|
Java API
java多线程之FutureTask、Future、CompletableFuture
java多线程之FutureTask、Future、CompletableFuture
254 0
|
Java
CompletableFuture总结和实践
CompletableFuture被设计在Java中进行异步编程。异步编程意味着在主线程之外创建一个独立的线程,与主线程分隔开,并在上面运行一个非阻塞的任务,然后通知主线程进展,成功或者失败。
345 0
|
消息中间件 Java 中间件
Future and CompletableFuture
Future代表异步执行的结果,也就是说异步执行完毕后,结果保存在Future里, 我们在使用线程池submit()时需要传入Callable接口,线程池的返回值为一个Future,而Future则保存了执行的结果 ,可通过Future的get()方法取出结果,如果线程池使用的是execute(),则传入的是Runnable接口 无返回值。
71 0
|
Java 调度
并发编程——Future & CompletableFuture
Java创建线程的方式,一般常用的是Thread,Runnable。如果需要当前处理的任务有返回结果的话,需要使用Callable。Callable运行需要配合Future。
56 0
|
Java 测试技术
CompletableFuture使用详解
CompletableFuture是jdk8的新特性。CompletableFuture实现了CompletionStage接口和Future接口
272 0
CompletableFuture使用详解