重要的参考资料:
从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());
}
}
}