• 二、CompletableFuture(一)基础概念


    一、基础

    Future:Future接口定义了操作异步任务执行的方法,如获取任异步任务的执行结果、取消异步任务的执行、判断任务执行是否完毕等。

    Callable:Callable接口定义了需要有返回结果的任务需要实现的方法。

    二、Future的缺点。

    阻塞。必须手动futureTask.get()查询执行结果,这样会造成阻塞,导致线程卡在get()方法处,等待返回结果,无法继续执行后续代码。

    解决方法:

    1、尽量使用带超时参数的get()方法。

    2、isDone()轮询是否结束,再调用get()。

    三、CompletableFuture

    public class CompletableFuture<T> implements Future<T>, CompletionStage<T>

    CompletionStage,代表异步计算过程中的某一个节点,一个阶段完成以后可以会触发另外一个阶段。

    一个阶段的计算执行可以是一个Function、Consumer或者Runnable。

    一个阶段的执行可能被单个阶段的完成触发,也可能时由多个阶段一起触发。

    1、两种实现方法 

    public static void main(String[] args) {
            try {
                CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
                    System.out.println("thread name :" + Thread.currentThread().getName());
                });
                System.out.println(future1.get());
    
                CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
                    System.out.println("thread name :" + Thread.currentThread().getName());
                    return 11;
                });
                System.out.println(future2.get());
            } catch (Exception e) {
            }
        }

    runAsync:无返回值

    supplyAsync:有返回值

    如果runAsync和supplyAsync没有指定线程池,则使用默认线程池ForkJoinPool.commonPool()。

    2、调用

        public static void main(String[] args) {
            try {
                //  自定义线程池
                ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 20, 1L,
                        TimeUnit.SECONDS, new LinkedBlockingQueue<>(50),
                        Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    
                CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                    try {
                        System.out.println(Thread.currentThread().getName() + "暂停3秒钟");
                        TimeUnit.SECONDS.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return 5;
                }, threadPoolExecutor).thenApply(i -> {
                    return i + 2;
                }).whenComplete((v, e) -> {
                    if (e == null) {
                        System.out.println("无异常,result:" + v);
                    }
                }).exceptionally(e -> {
                    e.printStackTrace();
                    return null;
                });
    
                System.out.println("----- main  -----");
    
                //  延迟关闭主线程,否则CompletableFuture默认使用的线程池会立刻关闭。
                //  当使用自定义线程池时,不用延长主线程。
    //            try {
    //                System.out.println("主线程暂停5秒钟关闭");
    //                TimeUnit.SECONDS.sleep(5);
    //            } catch (InterruptedException e) {
    //                e.printStackTrace();
    //            }
    
                System.out.println("----- main over -----");
                threadPoolExecutor.shutdown();
            } catch (Exception e) {
            }
        }

    3、优点

    异步任务结束时,会自动回调某个对象的方法。

    异步任务异常时,会自动回调某个对象的方法。

    主线程设置好回调后,不用关心异步任务的执行,异步任务之间可以顺序执行,不会发生阻塞。

    四、CompletableFuture Demo

    public class CompletableFutureNetMailDemo {
    
        static List<Mall> list = Arrays.asList(
                new Mall("jd"),
                new Mall("pdd"),
                new Mall("taobao"),
                new Mall("suning"),
                new Mall("dangdang"),
                new Mall("tmail")
        );
    
        /**
         * 同步
         */
        public static List<String> getPriceByStep(List<Mall> list, String productName) {
            return list.stream().map(mall -> String.format(productName + " in %s price is %.2f", mall.getMailName(), mall.calcPrice(productName))).collect(Collectors.toList());
        }
    
        /**
         * 异步
         */
        public static List<String> getPriceBySync(List<Mall> list, String productName) {
            return list.stream()
                    .map(mall -> CompletableFuture.supplyAsync(() -> String.format(productName + " in %s price is %.2f", mall.getMailName(), mall.calcPrice(productName))))
                    .collect(Collectors.toList())
                    .stream().map(CompletableFuture::join).collect(Collectors.toList());
        }
    
        public static void main(String[] args) {
            long startTime1 = System.currentTimeMillis();
            List<String> list1 = getPriceByStep(list, "test");
            for (String element : list1) {
                System.out.println(element);
            }
            long endTime1 = System.currentTimeMillis();
            System.out.println("--------- cost time:" + (endTime1 - startTime1) + "毫秒");
    
            System.out.println();
    
            long startTime2 = System.currentTimeMillis();
            List<String> list2 = getPriceBySync(list, "test");
            for (String element : list2) {
                System.out.println(element);
            }
            long endTime2 = System.currentTimeMillis();
            System.out.println("--------- cost time:" + (endTime2 - startTime2) + "毫秒");
    
        }
    }
    
    /**
     * 商城
     */
    @Data
    class Mall {
        private String mailName;
    
        public Mall(String mailName) {
            this.mailName = mailName;
        }
    
        /**
         * 随机价格
         */
        public double calcPrice(String productName) {
            //  检索1秒钟
            try {
                //System.out.println(Thread.currentThread().getName() + "检索商城1秒钟");
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //  返回价格
            return ThreadLocalRandom.current().nextDouble() * 2 + productName.charAt(0);
        }
    }
  • 相关阅读:
    本人作品
    转本笔记计算机理论
    markdown
    javascript的原型链解析(相信你也可以)
    思考 | 执行 delete from t1 where id = 10;MySQL会加什么锁?
    ORA00439: 未启用功能: Deferred Segment Creation
    思考 | select…for update会锁表还是锁行?
    DMS迁移MySQL源限制
    属性文件加载
    视频流推送到公网播放
  • 原文地址:https://www.cnblogs.com/shiblog/p/15711812.html
Copyright © 2020-2023  润新知