Java 最强并行(I/O密集型)方法

预备知识

调整线程池的大小,《Java 并发编程实战》中的公式

线程数 = Cpu 核心数 * 期望的 CPU 利用率(0和1之间) * (1 + 等待时间/计算时间)

  • CPU 核心数可以通过 Runtime.getRuntime.availableProcessors() 得到
  • 避免过载,最好设置线程数上限

并行:使用流还是 CompletableFuture ?

    • 计算密集型
    • 没有 I/O
    • 因为实现简单,同时效率也可能是最高的
  • CompletableFuture
    • 涉及等待 I/O 操作(包括网络连接)
    • 灵活性好(可以根据实际情况设置线程数)
    • 不使用并行流的原因之一:处理流的流水线中如果发生 I/O 等待,流的延迟特性会让我们很难判断到底什么时候触发了等待

核心代码

private final Executor executor =
        Executors.newFixedThreadPool(Math.min(shops.size(), 100), r -> {
            Thread t = new Thread(r);
            t.setDaemon(true);
            return t;
        });

CompletableFuture.supplyAsync(() -> shop.getName() + " price is" + shop.getPrice(product), executor)

完整代码

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * Java 最强并行
 * @author aoe
 * @date 2021/2/20
 */
public class BestParallel {

    private final List<Shop> shops = getShops(100);

    private final Executor executor =
            Executors.newFixedThreadPool(Math.min(shops.size(), 100), r -> {
                Thread t = new Thread(r);
                t.setDaemon(true);
                return t;
            });

    public static void main(String[] args) {
        BestParallel test = new BestParallel();

        long start = System.nanoTime();
        test.findPrices("car");
        long duration = (System.nanoTime() - start) / 1_000_000;
        System.out.println("普通版 done in " + duration + " msecs");
        // 15115

        start = System.nanoTime();
        test.findPricesBest("car");
        duration = (System.nanoTime() - start) / 1_000_000;
        System.out.println("最强版 done in " + duration + " msecs");
        // 1020
    }

    public List<String> findPrices(String product) {
        List<CompletableFuture<String>> priceFutures =
                shops.stream()
                        // 使用 CompletableFuture 以异步方式及时每种商品的价格
                        .map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is" + shop.getPrice(product))
                        )
                        .collect(Collectors.toList());
        return priceFutures.stream()
                // 等待所有异步操作结束
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
    }

    public List<String> findPricesBest(String product) {
        List<CompletableFuture<String>> priceFutures =
                shops.stream()
                        // 使用 CompletableFuture 以异步方式及时每种商品的价格
                        .map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is" + shop.getPrice(product), executor)
                        )
                        .collect(Collectors.toList());
        return priceFutures.stream()
                // 等待所有异步操作结束
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
    }

    private List<Shop> getShops(int count) {
        List<Shop> list = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            list.add(new Shop("Shop" + i));
        }
        return list;
    }
}

class Shop {

    private final String name;
    private final Random random;

    public Shop(String name) {
        this.name = name;
        random = new Random(name.charAt(0) * name.charAt(1) * name.charAt(2));
    }

    public String getPrice(String product) {
        double price = calculatePrice(product);
        Discount.Code code = Discount.Code.values()[random.nextInt(Discount.Code.values().length)];
        return name + ":" + price + ":" + code;
    }

    public double calculatePrice(String product) {
        Util.delay();
        return Util.format(random.nextDouble() * product.charAt(0) + product.charAt(1));
    }

    public String getName() {
        return name;
    }

}

class Discount {

    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.getDiscountCode());
    }

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

class Util {

    private static final Random RANDOM = new Random(0);
    private static final DecimalFormat formatter = new DecimalFormat("#.##", new DecimalFormatSymbols(Locale.US));

    public static void delay() {
        int delay = 1000;
        //int delay = 500 + RANDOM.nextInt(2000);
        try {
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static double format(double number) {
        synchronized (formatter) {
            return new Double(formatter.format(number));
        }
    }

    public static <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures) {
/*
    CompletableFuture<Void> allDoneFuture =
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
    return allDoneFuture.thenApply(v ->
        futures.stream()
            .map(future -> future.join())
            .collect(Collectors.<T>toList())
    );
*/
        return CompletableFuture.supplyAsync(() -> futures.stream()
                .map(future -> future.join())
                .collect(Collectors.<T>toList()));
    }

}

class Quote {

    private final String shopName;
    private final double price;
    private final Discount.Code discountCode;

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

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

    public String getShopName() {
        return shopName;
    }

    public double getPrice() {
        return price;
    }

    public Discount.Code getDiscountCode() {
        return discountCode;
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值