CompletableFuture优化代码!展示飞一般的速度

CompletableFuture异步编程


前言

基础讲解:同步和异步

同步:提交请求->等待服务器处理->处理完返回 期间客户端浏览器等待

异步:请求通过事件触发->服务器处理(无需等待)->处理完毕


提示:以下是本篇文章正文内容,下面案例可供参考

一、CompletableFuture运算范式

在这里插入图片描述

二、RemoteLoader.Java

代码如下(示例):

2.1 、LabelService.JAVA

在这里插入图片描述

三、Test

串行流示例

3.1五个调用五个接口!延时1秒

在这里插入图片描述

并行流示例

在这里插入图片描述

四、CompletableFuture基本使用

  CompletableFuture<String> future = new CompletableFuture<>();
        new Thread(() -> {
    
    
            try {
    
    
                future.complete("Finish");  //任务执行完成后 设置返回的结果
            } catch (Exception e) {
    
    
                log.error("CompletableFuture -> 任务线程出现异常", e);
            }
        }).start();
        System.out.println(future.join());       //获取任务线程返回的结果

4.1、exceptionally方法

4.1.1、exceptionally -> 回调异常处理

4.1.1.2、示例

  /*Java8不仅提供允许任务返回结果的supplyAsync,还提供了没有返回值的runAsync;
        让我们可以更加的关注业务的开发,不需要处理异常错误的管理*/
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    
    
            return "Future";
        }).exceptionally(throwable -> "Throwable exception message:" + throwable.getMessage());
        System.out.println(future.get());

4.2、allOf方法

假如我们要调用多个CompletableFuture,想计算包含关键字CompletableFuture结果的数量。可以使用CompletableFuture.allOf()达成目的。

List<String> webPageLinks = Arrays.asList(...)    // A list of 

List<CompletableFuture<String>> pageContentFutures = webPageLinks.stream()
        .map(webPageLink -> downloadWebPage(webPageLink))
        .collect(Collectors.toList());

CompletableFuture<Void> allFutures = CompletableFuture.allOf(
        pageContentFutures.toArray(new CompletableFuture[pageContentFutures.size()])
);

五、 CompletableFuture 测试

5.1、 注:CompletableFuture -> 注意阻塞

5.2 、join()方法

5.2.1 join()方法和get()方法非常类似,这唯一不同的地方是如果最顶层的CompletableFuture完成的时候发生了异常,它会抛出一个未经检查的异常

/*
         *使用异步计算处理调用接口方法
         */
        List<CompletableFuture<String>> completableFutureList = remoteLoaders.stream().map(
                loader ->
                        CompletableFuture.supplyAsync(loader::load)).collect(toList());

        /*
        *当所有future完成的时候,我们调用了future.join(),因此我们不会在任何地方阻塞。
        * */
        List<String> customerDetail = completableFutureList
                .stream()
                .map(CompletableFuture::join)
                .collect(toList());

        System.out.println(customerDetail);
        long end = System.currentTimeMillis();
        System.out.println("总共花费时间:" + (end - start));
       

5.3、 结果

在这里插入图片描述

5.4、自定义线程 newFixedThreadPool

    /*自定义线程池,优化CompletableFuture
使用并行流无法自定义线程池,但是CompletableFuture可以*/
 long start = System.currentTimeMillis();
        List<RemoteLoader> remoteLoaders = Arrays.asList(
                new RemoteLoader.CustomerInfoService(),
                new RemoteLoader.WatchRecordService(),
                new RemoteLoader.OrderService(),
                new RemoteLoader.LabelService(),
                new RemoteLoader.LearnRecordService()
        );

        /*线程自定义*/
        ExecutorService executorService = Executors.newFixedThreadPool(50);
        List<CompletableFuture<String>> completableFutureList = remoteLoaders.
                stream().map(
                loader -> CompletableFuture.supplyAsync(
                        loader::load,
                        executorService)).
                collect(toList());
        
        
        /*上述已经讲过这个stream的作用了*/ 
        List<String> customerDetail = completableFutureList.
                stream().
                map(CompletableFuture::join).
                collect(toList());
        
        System.out.println(customerDetail);
        long end = System.currentTimeMillis();
        System.out.println("总共花费时间:" + (end - start));

总结

这两者如何选择主要看任务类型,建议如果你的任务是计算密集型的,并且没有I/O操作的话,那么推荐你选择Stream的并行流。
实现简单并行效率也是最高的如果你的任务是有频繁的I/O或者网络连接等操作,那么推荐使用CompletableFuture。
采用自定义线程池的方式,根据服务器的情况设置线程池的大小,尽可能的让CPU忙碌起来

猜你喜欢

转载自blog.csdn.net/Daeker/article/details/112635797