二、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); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
2019-12-20 springcloud + vue + websocket