首页 > 其他分享 >CompletableFuture的简单使用

CompletableFuture的简单使用

时间:2022-08-25 17:23:38浏览次数:78  
标签:结果 简单 new 线程 使用 CompletableFuture executorService ThreadPoolExecutor

日常开发中,我们都会用到线程池,一般会用execute()和submit()方法提交任务。但是当你用过CompletableFuture之后,就会发现以前的线程池处理任务有多难用,功能有多简陋,CompletableFuture又是多么简洁优雅。

要知道CompletableFuture已经随着Java8发布7年了,还没有过它就有点说不过去了。

 一、线程池处理任务和CompletableFuture处理任务

1.1、使用线程池处理任务

 1     /**
 2      * 1. 使用线程池处理任务
 3      */
 4     @Test
 5     public void test1() throws ExecutionException, InterruptedException {
 6         // 1. 创建线程池
 7         ThreadPoolExecutor executorService = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
 8         List<Integer> list = Arrays.asList(1, 2, 3);
 9 
10         for (Integer key : list) {
11             // 2. 提交任务
12             Future<String> future = executorService.submit(() -> {
13                 // 睡眠一秒,模仿处理过程
14                 Thread.sleep(1000L);
15                 return "结果" + key;
16             });
17             // 3. 获取结果
18             System.out.println(future.get());
19         }
20         executorService.shutdown();
21     }

输出结果:

结果1
结果2
结果3

这里能够发现两个问题:

  1. 获取结果时,调用的future.get()方法,会阻塞当前线程,直到返回结果,大大降低性能
  2. 有一半的代码在写怎么使用线程,其实我们不应该关心怎么使用线程,更应该关注任务的处理

有没有具体的优化方案呢?当然有了,请出来我们今天的主角CompletableFuture

1.2、使用CompletableFuture处理任务

 1     /**
 2      * 使用CompletableFuture重构任务处理
 3      */
 4     @Test
 5     public void test2() {
 6         // 1. 创建线程池
 7         ThreadPoolExecutor executorService = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
 8 
 9         List<Integer> list = Arrays.asList(1, 2, 3);
10         for (Integer key : list) {
11             // 2. 提交任务
12             CompletableFuture.supplyAsync(() -> {
13                 // 睡眠一秒,模仿处理过程
14                 try {
15                     Thread.sleep(1000L);
16                 } catch (InterruptedException e) {
17                     e.printStackTrace();
18                 }
19                 return "结果" + key;
20             }, executorService).whenCompleteAsync((result, exception) -> {
21                 // 3. 获取结果
22                 System.out.println(result);
23             });
24         }
25 
26         executorService.shutdown();
27         // 由于whenCompleteAsync获取结果的方法是异步的,所以要阻塞当前线程才能输出结果
28         try {
29             Thread.sleep(2000L);
30         } catch (InterruptedException e) {
31             e.printStackTrace();
32         }
33     }

输出结果:

结果2
结果3
结果1

可以看到是ComparableFutrue是通过supplyAsync方法进行异步执行任务的。

=============================================================

可是上面的任务执行还是有一些问题的,需要阻塞当前线程输出结果,但是我们并不能确定线程的执行结束时间。也就无法准确设置线程阻塞时间,这样子就会导致最后执行的结果不对。

我们可以通过join进行优化一下:异步任务完成时统一返回结果值

 1     public void test2() {
 2         // 1. 创建线程池
 3         ThreadPoolExecutor executorService = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
 4 
 5         List<Integer> list = Arrays.asList(1, 2, 3);
 6         List<String> joinResult = new ArrayList<>();
 7         for (Integer key : list) {
 8             // 2. 提交任务
 9             String taskResult = CompletableFuture.supplyAsync(() -> {
10                 // 睡眠一秒,模仿处理过程
11                 try {
12                     Thread.sleep(1000L);
13                 } catch (InterruptedException e) {
14                     e.printStackTrace();
15                 }
16                 return "结果" + key;
17                 // 完成时返回结果值
18             }, executorService).join();
19             joinResult.add(taskResult);
20         }
21         executorService.shutdown();
22         // 3、打印结果
23         joinResult.forEach(System.out::println);
24     }

 

标签:结果,简单,new,线程,使用,CompletableFuture,executorService,ThreadPoolExecutor
From: https://www.cnblogs.com/zhangzhixi/p/16624757.html

相关文章

  • ckeditor5使用
    //引入<scriptsrc="../view/public/ckeditor5/build/ckeditor.js"></script><scriptsrc="../view/public/ckeditor5/build/translations/zh.js"></script>//组件<t......
  • localStorge在react中的使用
    1.什么时候用,在哪里用刚获取数据的时候,进行设置,localStorge.setItem(key,value);因为localStorge是用来作为缓存的,且有一定的延时,尤其是在本页面设置本页面使用时,所以,依然......
  • 在本地使用Markdown来写作,自动同步文章笔记到印象笔记(马克飞象替代方案)
    在本地使用 MarkdownPad 、Mark 、Typora 、VSCode 任意你喜欢的 Markdown 编辑器进行文档编写,本工具将自动同步文档到印象笔记。可以当做是马克飞象的替代方案。......
  • vim使用
    把CapsLock映射成。这个操作我建议使用操作系统的改键工具来完成。win下的修改教程链接,mac下直接在系统设置中改即可。不推荐在vim中改是因为系统内修改一次,所有能开启vi......
  • ubuntu查看系统使用内核版本-下载对应源码-国内kernel.org镜像
    查看系统Linux内核版:$apt-cachesearchlinux-source -   下载源码:$sudoapt-getinstalllinux-source-5.3.0 -  下载完成,到/usr/src目录查......
  • Vue项目使用高德地图
    流程:注册账号获取KEY安装使用注册链接:https://lbs.amap.com/选择Web端(JSAPI),同时需要域名限制请按提示进行输入:创建完成后即可看到KEY。安装高德地图JSAPI......
  • 使用{{}}展示或更新页面数据时出现闪烁问题:当网速比较慢时,会让用户先看到表达式{{msg}
    可使用以下方式解决:1、使用v-cloak指令,然后为其设置css样式display:none;即上述代码可修改为:但有时添加完毕后变量仍会显示(即闪烁问题没解决),这是因为v-cloak 的displa......
  • vue2的nextTick使用
    1、关于nextTick。vue中的Dom更新是异步的,是异步的意味着当被处理数据是动态变化时,此时对应的Dom未能及时更新(同步更新)就会导致数据已经更新(model层已经更新)而视力层未更......
  • kibana 使用
    kibana官方地址:https://www.elastic.co/guide/en/kibana/7.8/xpack-security.htmlIndexManagementViewindexsettings,mappings,andstatisticsandperformoperati......
  • Wireshark软件使用教程
    引用网址:https://www.cnblogs.com/cainiao-chuanqi/p/15910553.htmlWireshark是非常流行的网络封包分析软件,可以截取各种网络数据包,并显示数据包详细信息。常用于开发测试......