简单的任务,用Future获取结果还好,但我们并行提交的多个异步任务,往往并不是独立
的,很多时候业务逻辑处理存在串行[依赖]、并行、聚合的关系。如果要我们手动用 Fueture
实现,是非常麻烦的。
       CompletableFuture是Future接口的扩展和增强。CompletableFuture实现了Future接
口,并在此基础上进行了丰富地扩展,完美地弥补了Future上述的种种问题。更为重要的是,
CompletableFuture实现了对任务的编排能力。借助这项能力,我们可以轻松地组织不同任
务的运行顺序、规则以及方式。从某种程度上说,这项能力是它的核心能力。而在以往,虽然
通过CountDownLatch等工具类也可以实现任务的编排,但需要复杂的逻辑处理,不仅耗费精
力且难以维护。

  • 代码结构

  • 代码简要描述
  1. TestFuture:
    通过用户点餐吃饭场景,模拟测试CompletableFuture的串行[依赖]、并行、聚合功能;实现了非依赖业务的并行处理和强依赖业务的顺序执行。
    
  2. MyThreadPool:
    自定义线程池,避免几个特别耗时的任务拖垮整个应用的风险。
  3. MyThreadFactory:
    自定义线程名称,方便异常排查。
  • 测试结果

  • 代码
TestFuture
package com.concurrent.demo;import com.concurrent.demo.config.MyThreadPool;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.StopWatch;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;/*** @ClassName TestFuture* @Description TestFuture* @Author LyinQi* @Date 2022/1/11 14:51* @Version 1.0*/
@SpringBootTest
public class TestFuture {@Autowiredprivate MyThreadPool myThreadPool;@Testvoid TestFuture() throws ExecutionException, InterruptedException, TimeoutException {// 并行处理测试 地三鲜// 并行处理: 切土豆/切茄子/切西红柿/切葱姜蒜// 顺序执行: 配菜准备齐全了 -> 起锅烧油 -> 炒菜// 并行执行: 蒸米饭// 最终: 开饭了long sTime = System.currentTimeMillis();Thread thread = Thread.currentThread();System.err.println(thread.getName() + "=====老板来份地三鲜=====" + "用时:" + (System.currentTimeMillis()-sTime) + "ms");CompletableFuture<String> tdFuture = CompletableFuture.supplyAsync(() -> {StopWatch stopWatch = new StopWatch("土豆");stopWatch.start();Thread t = Thread.currentThread();System.err.println(t.getName() + "=ing正在准备土豆");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}stopWatch.stop();System.err.println(">>>>>>>>>>>" + stopWatch.getId() + "用时:" + stopWatch.getTotalTimeMillis() + "ms");return t.getName() + "=over土豆准备好了";}, myThreadPool.instance());System.err.println(thread.getName() + "=====点完餐我去玩手机了,坐等开饭=====");CompletableFuture<String> qzFuture = CompletableFuture.supplyAsync(() -> {StopWatch stopWatch = new StopWatch("茄子");stopWatch.start();Thread t = Thread.currentThread();System.err.println(t.getName() + "=ing正在准备茄子");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}stopWatch.stop();System.err.println( ">>>>>>>>>>>" + stopWatch.getId() + "用时:" + stopWatch.getTotalTimeMillis() + "ms");return t.getName() + "=over茄子准备好了";}, myThreadPool.instance());CompletableFuture<String> xhsFuture = CompletableFuture.supplyAsync(() -> {StopWatch stopWatch = new StopWatch("西红柿");stopWatch.start();Thread t = Thread.currentThread();System.err.println(t.getName() + "=ing正在准备西红柿");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}stopWatch.stop();System.err.println( ">>>>>>>>>>>" + stopWatch.getId() + "用时:" + stopWatch.getTotalTimeMillis() + "ms");return t.getName() + "=over西红柿准备好了";}, myThreadPool.instance());CompletableFuture<String> cjsFuture = CompletableFuture.supplyAsync(() -> {StopWatch stopWatch = new StopWatch("葱姜蒜");stopWatch.start();Thread t = Thread.currentThread();System.err.println(t.getName() + "=ing正在准备葱姜蒜");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 抛出个异常试试
//            int err = 2/0;stopWatch.stop();System.err.println( ">>>>>>>>>>>" + stopWatch.getId() + "用时:" + stopWatch.getTotalTimeMillis() + "ms");return t.getName() + "=over葱姜蒜准备好了";}, myThreadPool.instance());CompletableFuture<Void> allOf = CompletableFuture.allOf(tdFuture, qzFuture, xhsFuture, cjsFuture);// TODO 注:虽然allof.get()方法并不会返回任何数据,但是如果不调用get()方法,主线程不会阻塞等待所有异步线程的处理结果allOf.get(4,TimeUnit.SECONDS);System.err.println(thread.getName() + "=====配菜已经都准备齐全了=====" + "用时:" + (System.currentTimeMillis()-sTime) + "ms");// 炒菜CompletableFuture<String> ccFuture = CompletableFuture.supplyAsync(() -> {StopWatch stopWatch = new StopWatch("起锅烧油");stopWatch.start();Thread t = Thread.currentThread();System.err.println(t.getName() + "=ing起锅烧油");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}stopWatch.stop();System.err.println(">>>>>>>>>>>" + stopWatch.getId() + "用时:" + stopWatch.getTotalTimeMillis() + "ms");return t.getName() + "=over油好了";}, myThreadPool.instance()).thenApplyAsync(s -> {StopWatch stopWatch = new StopWatch("炒菜");stopWatch.start();Thread t = Thread.currentThread();System.err.println(t.getName() + s + "=ing开始炒菜");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}stopWatch.stop();System.err.println(">>>>>>>>>>>" + stopWatch.getId() + "用时:" + stopWatch.getTotalTimeMillis() + "ms");return t.getName() + "=over地三鲜准备好了";},myThreadPool.instance());// 蒸米饭CompletableFuture<String> mfFuture = CompletableFuture.supplyAsync(() -> {StopWatch stopWatch = new StopWatch("蒸米饭");stopWatch.start();Thread t = Thread.currentThread();System.err.println(t.getName() + "=ing开始蒸米饭");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}stopWatch.stop();System.err.println(">>>>>>>>>>>" + stopWatch.getId() + "用时:" + stopWatch.getTotalTimeMillis() + "ms");return t.getName() + "=over米饭蒸好了";}, myThreadPool.instance());// 等待全部准备好CompletableFuture<Void> allOf1 = CompletableFuture.allOf(ccFuture, mfFuture);allOf1.get(6,TimeUnit.SECONDS);System.err.println(thread.getName() + "=====饭菜都准备齐全了=====" + "用时:" + (System.currentTimeMillis()-sTime) + "ms");System.err.println(thread.getName() +"="+ ccFuture.get());System.err.println(thread.getName() +"="+ mfFuture.get());// 开饭了System.err.println(thread.getName() + "=====开饭了=====" + "用时:" + (System.currentTimeMillis()-sTime) + "ms");// 延时1秒,防止异步线程未执行完毕,单元测试提前结束.try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.err.println(thread.getName() + "=====over=====" + "用时:" + (System.currentTimeMillis()-sTime) + "ms");}}
MyThreadPool
package com.concurrent.demo.config;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.concurrent.*;/*** @ClassName CommonThreadPool* @Description CommonThreadPool* @Author LyinQi* @Date 2022/1/10 13:53* @Version 1.0*/
@Component
public class MyThreadPool {private ExecutorService executorService;public ExecutorService instance(){return this.executorService;}@PostConstructprivate void init(){if(this.executorService == null){// 获取最佳线程个数int nThreads = Runtime.getRuntime().availableProcessors()*2;// 创建固定数量的线程池ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(// 核心线程数量nThreads,// 最大线程数量nThreads*2,// 空闲线程超时时间600,// 空闲线程超时时间单位TimeUnit.SECONDS,// 任务队列模式(有界队列200)new ArrayBlockingQueue<Runnable>(200),// 线程工厂new MyThreadFactory("MyThread"),// 拒绝策略new ThreadPoolExecutor.CallerRunsPolicy());this.executorService = threadPoolExecutor;}}
}
MyThreadFactory
package com.concurrent.demo.config;import org.springframework.util.StringUtils;import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;/*** @ClassName MyThreadFactory* @Description MyThreadFactory* @Author LyinQi* @Date 2022/1/10 17:30* @Version 1.0*/
public class MyThreadFactory implements ThreadFactory {private static final AtomicInteger poolNumber = new AtomicInteger(1);private final ThreadGroup group;private final AtomicInteger threadNumber = new AtomicInteger(1);private final String namePrefix;MyThreadFactory(String name) {SecurityManager s = System.getSecurityManager();group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();if(!StringUtils.hasText(name)){name = "pool";}namePrefix = name + "-" +poolNumber.getAndIncrement() +"-thread-";}@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);if (t.isDaemon())t.setDaemon(false);if (t.getPriority() != Thread.NORM_PRIORITY)t.setPriority(Thread.NORM_PRIORITY);return t;}
}

CompletableFuture模拟复杂场景使用测试。。。相关推荐

  1. 【CompletableFuture模拟真实场景之性能优化】

    前言 在项目开发中,后端服务对外提供API接口一般都会关注响应时长.但是某些情况下,由于业务规划逻辑的原因,我们的接口可能会是一个聚合信息处理类的处理逻辑,比如我们从多个不同的地方获取数据,然后汇总处 ...

  2. 手机怎么模拟弱网_手游测试之模拟弱网环境测试

    为什么要做弱网环境测试? 其实现在不论是端游.手游还是页游,在国内范围来说,我们一般情况下网速都不算差了.而且随着5G的逐渐普及,相信网速对于玩家的制约会更小,玩家的体验也会有一个质的变化. 那我们为 ...

  3. 模拟业务场景往kafka推送消息的方法

    前言 项目最近需要接入一个推送功能,之前都是用云端内部接口模拟推送诊修消息的,但是实际触发场景是:诊修服务会将消息下发到kafka充当生产者,然后kafka推送给下游云端进行消费,所以,要模拟生产者往 ...

  4. 模拟问路场景理解递归

    递归:函数内部调用自己 1 # TODO:模拟问路场景理解递归 2 person_list = ['chen', 'wang', 'li', 'liu'] 3 def say_way(person_l ...

  5. unity 地图编辑器_基于Unity的场景基础测试

    场景作为游戏的一个基本构成元素,其功能.效果和性能的重要程度不言而喻.良好的场景表现是游戏留存率的重要因素,因此,QA对场景的测试需要格外注意. 场景的测试一般分为基础功能.效果.性能三方面.基础功能 ...

  6. 实战一:模拟手机充值场景

    编写Python程序,模拟以下场景: 计算机输出:欢迎使用XXX充值业务,请输入充值金额: 用户输入:100 计算机输出:充值成功,您本次充值100元. 代码: a = input("欢迎使 ...

  7. fiddler--通过Fiddler模拟弱网进行测试

    弱网测试的目的: 弱网测试可以发现一些因为网络问题导致的交互问题,从而更好的完善应用的性能. 关注点: 1.卡死,崩溃,无响应,闪退. 2.业务交互数据传输正确性. 通过Fiddler可以模拟弱网进行 ...

  8. AISHELL-2021E-EVAL 法律庭审场景语音测试数据集

    法律庭审场景语音测试数据集 语音识别实验评测 Speech Recognition Evaluation DATA Information Total Time  1 Hours Sampling R ...

  9. 腾讯优测优分享 | 分布式系统测试的应用方法——场景注入测试

    腾讯优测是专业的移动云测试平台,提供自动化测试-全面兼容性测试,云真机-远程真机租用,漏洞分析等多维度的测试服务! 在大数据浪潮下,海量数据处理能力的提升是推动大数据不断前行的基础.俗话说,工欲善其事 ...

  10. 基于Matlab的合成孔径雷达模拟陆地场景(附源码)

    目录 一.生成模拟地形 二.指定搜救系统和场景 三.定义地表反射率 四.配置雷达收发器 4.1 生成数据多维数据集 4.2 可视化 SAR 数据 五.总结 六.程序 合成孔径雷达(SAR)系统使用平台 ...

最新文章

  1. 用 TypeScript 编写一个 React 服务端渲染库(1)
  2. ZjDroid工具介绍及脱壳详细示例
  3. liunx 加入域控_让Linux使用Windows域控制器做用户认证
  4. 谈谈我的编程之路---WAMP(二)
  5. 整数序列(牛客,线段树)
  6. 树莓派超声波模块测距
  7. java证书的安装_Java 第三方证书安装
  8. stm32+lwip(四):网页服务器测试
  9. linux ps进程管理命令,Linux 进程管理命令之ps
  10. 广度优先搜索——填涂颜色(洛谷 P1162)
  11. Pandas 文本数据方法 startswith( ) endwith( )
  12. python 编译成exe黑屏_python''外星人入侵''打包成exe遇到的问题和解决办法,闪退,黑屏。...
  13. 虚拟环境安装python3
  14. MySQL latch小结
  15. ios申请企业开发者账号的代理_苹果企业开发者账号的申请详解
  16. 《关键信息基础设施安全保护条例》正式发布
  17. MIDAS:混频数据回归
  18. 避坑外连腾讯云服务器redis 6379
  19. 中国宠物医疗市场产业消费需求及盈利前景预测报告(2022-2027年)
  20. CS224N笔记(四) Lecture 7:循环神经网络RNN的进阶——LSTM与GRU

热门文章

  1. [转]高分一号的落后与特色
  2. 蓝桥杯2020第二场JAVA C真题
  3. 面试必考:在 Java 中如何利用 redis 实现一个分布式锁服务
  4. ESLint语法检查
  5. 使用VLC在web页面显示海康威视实时监控
  6. 【修电脑】每次关机提示rundll32.exe程序没有响应,修改注册表解决问题
  7. php生成数字订单号,php生成订单号函数
  8. 190824-英雄联盟传记爬取
  9. Python 01--介绍、基本语法、流程控制
  10. 深度剖析U8系统前后台数据关系-王成军-专题视频课程