二、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);
    }
}

 

posted @ 2021-12-20 17:29  幻月hah  阅读(186)  评论(0编辑  收藏  举报