Java多线程编程-10 J.U.C之CompletableFuture

重要的参考资料:
从CompletableFuture到异步编程设计
聊聊java高并发系统之异步非阻塞
商品详情页系统的Servlet3异步化实践

下面一个简单的例子说明CompletableFuture异步编排的使用:

public class CompletableFuturePerformance {

    // 使用自定义的线程池(如果使用默认ForkJoinPool,开启的线程数为parallelism(cpu核心数-1),执行时间会略有延长)
    // 程序空闲60s后会自动停止,因为keepAliveTime = 60
    static ExecutorService executor = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        ShopPrice parallelStreamTest = new ParallelStreamTest();
        ShopPrice completableFutureTest = new CompletableFutureTest();
        System.out.println("ParallelStream -> " + parallelStreamTest.findPrice("java8实战"));
        long duration = System.currentTimeMillis() - start;
        System.out.println("findPrice总消耗时间:" + duration + "毫秒"); // 并行流需2s,因为我的电脑是4核,但是有5个任务

        start = System.currentTimeMillis();
        System.out.println("CompletableFuture -> " + completableFutureTest.findPrice("java8实战"));
        duration = System.currentTimeMillis() - start;
        System.out.println("findPrice总消耗时间:" + duration + "毫秒");

        start = System.currentTimeMillis();
        System.out.println("ParallelStream -> " + parallelStreamTest.findPriceWithDiscount("java8实战"));
        duration = System.currentTimeMillis() - start;
        System.out.println("findPriceWithDiscount总消耗时间:" + duration + "毫秒");

        start = System.currentTimeMillis();
        System.out.println("CompletableFuture -> " + completableFutureTest.findPriceWithDiscount("java8实战"));
        duration = System.currentTimeMillis() - start;
        System.out.println("findPriceWithDiscount总消耗时间:" + duration + "毫秒");


        start = System.currentTimeMillis();
        System.out.println("CompletableFuture -> " + completableFutureTest.findPriceWithDiscountAsync("java8实战"));
        duration = System.currentTimeMillis() - start;
        System.out.println("findPriceWithDiscountAsync总消耗时间:" + duration + "毫秒");

    }

    private interface ShopPrice {
        List<String> findPrice(String product);
        List<String> findPriceWithDiscount(String product);
        default List<Double> findPriceWithDiscountAsync(String product) {
            return null;
        }
    }


    static List<Shop> shops = Arrays.asList(
            new Shop("TAO BAO"),
            new Shop("淘宝"),
            new Shop("拼多多"),
            new Shop("京东商城"),
            new Shop("天猫商城"));

    /**
     * 价格解析类
     *
     * @author lsg
     */
    public static class Quote {
        private final String shopName;
        private final double price;
        private final Discount.Code code;

        public Quote(String shopName, double price, Discount.Code code) {
            this.shopName = shopName;
            this.price = price;
            this.code = code;
        }

        public String getShopName() {
            return shopName;
        }

        public double getPrice() {
            return price;
        }

        public Discount.Code getCode() {
            return code;
        }

        public static Quote parse(String s){
            String[] arr = s.split(":");
            return new Quote(arr[0], Double.valueOf(arr[1]), Discount.Code.valueOf(arr[2]));
        }
    }

    public static class Shop {

        private String name;
        private Random random = new Random();

        public Shop(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        /**
         * 直接获取价格
         * @param product
         * @return
         */
        public double getPrice(String product) {
            return calculatePrice(product);
        }

        /**
         * 获取价格描述信息
         * @param product
         * @return
         */
        public String getPrice2(String product){
            double price = calculatePrice(product);
            Discount.Code code = Discount.Code.values()[random.nextInt(Discount.Code.values().length)];
            return String.format("%s:%.2f:%s", name, price, code);
        }

        //异步获取价格
        public Future<Double> getPriceAsync(String product) {
            return CompletableFuture.supplyAsync(() ->
                    calculatePrice(product)
            );
        }

        //模拟获取价格的服务
        private double calculatePrice(String product) {
            delay();
            return random.nextDouble() * product.charAt(0) + product.charAt(1);
        }
    }

    public static class Discount {
        public static double getRate() {
            delay();
            return 1d;
        }

        public enum Code{
            NONE(0),SILVER(5),GOLD(10),PLATINUM(15),DIAMOND(20);

            private final int percentage;
            Code(int percentage){
                this.percentage = percentage;
            }
        }

        public static String applyDiscount(Quote quote){
            return quote.getShopName() + " price is " + Discount.apply(quote.getPrice(),quote.getCode());
        }


        public static double apply(double price, Code code){
            delay();
            return  price * (100 - code.percentage) /100 ;
        }
    }

    //模拟延迟1s
    private static void delay() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static class ParallelStreamTest implements ShopPrice {
        public List<String> findPrice(String product){
            return shops.parallelStream()
                    .map(shop -> String.format("%s 的价格是 %.2f", shop.getName(),shop.getPrice(product)))
                    .collect(toList());

        }
        public List<String> findPriceWithDiscount(String product){
            return shops.parallelStream()
                    .map(shop -> shop.getPrice2(product)) //获取原始报价
                    .map(Quote::parse) //解析报价字符串
                    .map(Discount::applyDiscount) //调用折扣服务应用报价折扣
                    .collect(toList());
        }
    }

    public static class CompletableFutureTest implements ShopPrice{
        public List<String> findPrice(String product) {

            List<CompletableFuture<String>> priceFuture = shops.stream()
                    .map(shop -> CompletableFuture.supplyAsync( // 使用异步的方式计算每种商品的价格
                            () -> shop.getName() + " 的价格是 " + shop.getPrice(product), executor))
                    .collect(toList());

            return priceFuture.stream()
                    .map(CompletableFuture::join) //join 操作等待所有异步操作的结果
                    .collect(toList());
        }

        public List<String> findPriceWithDiscount(String product){
            List<CompletableFuture<String>> priceFuture = shops.stream()
                    .map(shop -> CompletableFuture.supplyAsync( // 异步获取价格
                            () -> shop.getPrice2(product),executor))
                    .map(future -> future.thenApply(Quote::parse)) // 获取到价格后对价格解析
                    .map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync( // 另一个异步任务构造异步应用报价
                            () -> Discount.applyDiscount(quote),executor)))
                    .collect(toList());

            return priceFuture.stream()
                    .map(CompletableFuture::join) //join 操作和get操作有相同的含义,等待所有异步操作的结果。
                    .collect(toList());
        }

        public List<Double> findPriceWithDiscountAsync(String product) {
            List<CompletableFuture<Double>> priceFuture = shops.stream()
                    .map(shop -> CompletableFuture.supplyAsync( // 异步获取价格
                            () -> shop.getPrice(product),executor))
                    .map(future -> future.thenCombine(CompletableFuture.supplyAsync( // 异步获取折扣率
                            () -> Discount.getRate(),executor)
                            , (price, rate) -> price * rate)) // 将两个异步任务的结果合并
                    .collect(toList());
            return priceFuture.stream()
                    .map(CompletableFuture::join) //join 操作和get操作有相同的含义,等待所有异步操作的结果。
                    .collect(toList());
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值