CompletableFuture
CompletableFuture的简单介绍
-
在Java8中,CompleteableFuture提供了非常强大的Future的拓展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合CompleteableFuture的方法。
-
它可能代表一个明确完成的Future,也有可能代表一个完成阶段(CompletionStages),它支持在计算完成以后触发一些函数或执行某些动作。
-
它实现了Future和CompletionStage接口
CompletableFuture的核心的四个静态方法
// 创建一个异步操作 并且有返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
// 创建一个异步操作 并且有返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}
// 创建一个异步操作 无返回值
public static CompletableFuture<Void> runAsync(Runnable runnable) {
return asyncRunStage(asyncPool, runnable);
}
// 创建一个异步操作 无返回值
public static CompletableFuture<Void> runAsync(Runnable runnable,
Executor executor) {
return asyncRunStage(screenExecutor(executor), runnable);
}
- 简单代码演示
package com.lichennan;
import java.util.concurrent.*;
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 线程工厂
ThreadFactory t1 = r -> new Thread(r,"demo1" + ThreadLocalRandom.current().nextInt(100));
// 自定义线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(12, 24, 30, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(2000), t1);
// 任务一
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> System.out.println(Thread.currentThread().getName() + "执行任务1"), threadPool);
// 任务二
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "执行任务2");
return 1;
}, threadPool);
System.out.println(future.get());
System.out.println(future1.get());
}
}
demo15执行任务1 null demo185执行任务2 1
函数式编程小总结
应用
-
需求:
我们去比同一个商品在各个平台上的价格,要求获得一个清单列表,
1 step by step,查完京东查淘宝,查完淘宝查天猫......
2 all 一口气同时查询。。。。。
-
代码实现
package com.lichennan; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; public class NetMallDemo { /** * 电商网站 */ static List<NetMall> list = Arrays.asList( new NetMall("jd"), new NetMall("tb"), new NetMall("pdd") ); public static void main(String[] args) { long l = System.currentTimeMillis(); List<String> list1 = list(list, "Java并发编程的艺术"); list1.forEach(System.out::println); System.out.println(System.currentTimeMillis()-l); } /** * 获取各电商网站商品价格 * * @param list 列表 * @param productName 产品名称 * @return {@link List}<{@link String}> */ public static List<String> list(List<NetMall> list, String productName){ return list.stream() .map(m->CompletableFuture.supplyAsync(()->String.format(productName + " %s price is %.2f", m.getNetMallName(), m.getPriceByName(productName)))) .collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList()); } } /** * 电商网站 * @author licn9901@163.com * @date 2022/12/15 */ class NetMall { private String netMallName; public NetMall(String netMallName) { this.netMallName = netMallName; } public double getPriceByName(String productName) { return calcPrice(productName); } private double calcPrice(String productName) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return ThreadLocalRandom.current().nextDouble() + productName.charAt(0); } public String getNetMallName() { return netMallName; } }Java并发编程的艺术 jd price is 74.21 Java并发编程的艺术 tb price is 74.30 Java并发编程的艺术 pdd price is 74.44 1085
CompletableFuture常用方法
-
获得结果和触发计算
-
获取结果
public T get() // 不见不散 public T get(long timeout, TimeUnit unit) // 过时不候 // 没有计算完成的情况下,有一个替代结果 // 立即获取结果不阻塞 计算完,返回计算完成后的结果,没算完,返回设定的valueIfAbsent值 public T getNow(T valueIfAbsent) public T join() -
主动触发计算
public boolean complete(T value) // 是否打断get方法立即返回括号值 -
代码演示
/** * 获得结果和触发计算 */ public static void test1() throws ExecutionException, InterruptedException, TimeoutException { // 不见不散 System.out.println(CompletableFuture .supplyAsync(() -> 1) .get()); System.out.println(CompletableFuture .supplyAsync(() -> 1) .join()); // 过时不候 System.out.println(CompletableFuture.supplyAsync(()->{ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } return 3; }).get(4,TimeUnit.SECONDS)); // 立即获取结果不阻塞 计算完,返回计算完成后的结果,没算完,返回设定的valueIfAbsent值 System.out.println(CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } return 3; }).getNow(2)); // 是否打断get方法立即返回括号值 CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } return 3; }); System.out.println(future.complete(4)+" "+future.get()); }
-
-
对计算结果进行处理
-
thanApply
// 计算结果存在依赖关系,这两个线程串行化 // 由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停。 System.out.println(CompletableFuture .supplyAsync(() -> 1) .thenApply(f -> { //int i = 1/0; return f + 2; }).thenApply(f1->{ return f1 + 2; }).get()); -
handle
// 有异常也可以往下走一步,根据带的异常参数可以进一步处理 // 有异常也可以往下走一步,根据带的异常参数可以进一步处理 System.out.println(CompletableFuture.supplyAsync(() -> 1) .handle((f,e) -> { //int i = 1/0; return f + 2; }).handle((f1,e)-> f1 + 2).whenCompleteAsync((f, e)->{ System.out.println(f); }).exceptionally(e->{ e.printStackTrace(); return null; }).get());
-
-
对计算结果进行消费
// 接收任务的处理结果,并消费处理,无返回结果 // thenAccept CompletableFuture .supplyAsync(() -> 1) .thenApply(f -> f + 2) .thenApply(f -> f + 3) .thenApply(f -> f + 4) .thenAccept(System.out::println);任务之间的顺序执行
thenRun:任务A执行完执行B,并且B不需要A的结果
thenAccept: 任务A执行完执行B,B需要A的结果,但是任务B无返回值
thenApplay:任务A执行完毕执行B,B需要A的结果,同时任务B有返回值
-
对计算速度进行选用
// 谁快用谁 public static void test4() throws ExecutionException, InterruptedException { CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> { System.out.println(Thread.currentThread().getName() + "\t" + "---come in "); //暂停几秒钟线程 try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return 10; }); CompletableFuture completableFuture2 = CompletableFuture.supplyAsync(() -> { System.out.println(Thread.currentThread().getName() + "\t" + "---come in "); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return 20; }); // future1和future2那个快用那个 CompletableFuture thenCombineResult = completableFuture1.applyToEither(completableFuture2,f -> { System.out.println(Thread.currentThread().getName() + "\t" + "---come in "); return f + 1; }); System.out.println(Thread.currentThread().getName() + "\t" + thenCombineResult.get()); } -
对计算结果进行合并
// 两个CompletionStage任务都完成后,最终能把两个任务的结果一起交给thenCombine 来处理 // 先完成的先等待 public static void test5() throws ExecutionException, InterruptedException { CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> { System.out.println(Thread.currentThread().getName() + "\t" + "---come in "); //暂停几秒钟线程 try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return 10; }); CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> { System.out.println(Thread.currentThread().getName() + "\t" + "---come in "); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return 20; }); // 任务1,任务2一起完成 System.out.println(completableFuture1.thenCombine(completableFuture2, (f1, f2) -> { return f1 + f2; }).get()); }