参考文档:https://blog.csdn.net/u014373554/article/details/109473443
使用阻塞队列+线程池实现异步消费
1. 定义任务队列
/**
* 定义队列
*/
private static LinkedBlockingDeque<String> deque = new LinkedBlockingDeque<>();
2. 定义线程池(单例、单线程)
线程池只可以有单个线程,这样才可以保证消费队列内容时是顺序的,多线程时会导致重复消费。
线程池需要使用常量存放,避免每次使用时创建新的线程池,而变成多个线程并发操作,也会导致重复消费。
/**
* 消费者,单一线程, 进行处理业务逻辑
*/
public static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
3. 存储任务和顺序消费逻辑
/**
* 模拟数据库存放数据,并保证不重复
*/
private List<String> strList = new ArrayList<>();
/**
* 服务请求生成任务存放至队列,并调用线程消费队列
*/
@PostMapping("/process")
public void process(String equipmentNo) {
if (StringUtils.isEmpty(equipmentNo)) {
log.info("参数不能为空");
}
try {
if(deque.remainingCapacity() > 0){
deque.put(equipmentNo);
}else {
log.info("队列已经满了,请稍后重试");
}
EXECUTOR_SERVICE.submit(() ->{
//开始处理请求队列中的请求,按照队列的FIFO的规则,先处理先放入到队列中的请求
while (deque != null && deque.size() > 0){
//处理请求
try {
String orderNo = deque.take();
if(!strList.contains(orderNo)){
log.info("处理订单号:{}",orderNo);
strList.add(orderNo);
}
} catch (InterruptedException e) {
log.info("处理订单号发生异常,异常信息:{}",e);
}
}
});
} catch (InterruptedException e) {
log.info("处理发生异常,异常信息:{}",e);
}
}
@GetMapping("/query")
public List<String> query() {
log.info("获取strList");
return strList;
}
- Executors.newSingleThreadExecutor() 线程池中只有一个线程,而线程中队列是无界队列,如果短时间生产大量任务,可能会导致内存溢出
使用 Jmeter 进行并发测试
下载 Binaries 文件,解压后运行 jmeter.bat 即可启动 jmeter 程序
- 打开程序后,在当前测试项目下,添加线程组,并配置并发数量和启动时间
- 在当前线程组下,添加 HTTP 请求信息,可以配置请求信息(地址、参数等)
- 在当前测试项目下,添加测试报告,显示并发测试信息