SpringBoot 引入线程池+Queue缓冲队列实现高并发下单业务
点击关注公众号,Java干货及时送达👇

来源:blog.csdn.net/u011677147/article/details/80271174
1.首先是springBoot的项目框架如下: 2.业务测试流程涉及的类,如下 3.使用JMeter模拟并发下单请求 4.结果
主要是自己在项目中(中小型项目) 有支付下单业务(只是办理VIP,没有涉及到商品库存),目前用户量还没有上来,目前没有出现问题,但是想到如果用户量变大,下单并发量变大,可能会出现一系列的问题,趁着空闲时间,做了这个demo测试相关问题。
可能遇到的问题如下:
订单重复 高并发下,性能变慢
解决方式:ThreadPoolExecutor线程池 + Queue队列
1.首先是springBoot的项目框架如下:

2.业务测试流程涉及的类,如下
BusinessThread 类
package com.springboot.demo.Threads;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")//spring 多例
public class BusinessThread implements Runnable{
private String acceptStr;
public BusinessThread(String acceptStr) {
this.acceptStr = acceptStr;
}
public String getAcceptStr() {
return acceptStr;
}
public void setAcceptStr(String acceptStr) {
this.acceptStr = acceptStr;
}
@Override
public void run() {
//业务操作
System.out.println("多线程已经处理订单插入系统,订单号:"+acceptStr);
//线程阻塞
/*try {
Thread.sleep(1000);
System.out.println("多线程已经处理订单插入系统,订单号:"+acceptStr);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
}
TestThreadPoolManager 类
package com.springboot.demo.Threads;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.*;
@Component
public class TestThreadPoolManager implements BeanFactoryAware {
//用于从IOC里取对象
private BeanFactory factory; //如果实现Runnable的类是通过spring的application.xml文件进行注入,可通过 factory.getBean()获取,这里只是提一下
// 线程池维护线程的最少数量
private final static int CORE_POOL_SIZE = 2;
// 线程池维护线程的最大数量
private final static int MAX_POOL_SIZE = 10;
// 线程池维护线程所允许的空闲时间
private final static int KEEP_ALIVE_TIME = 0;
// 线程池所使用的缓冲队列大小
private final static int WORK_QUEUE_SIZE = 50;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
factory = beanFactory;
}
/**
* 用于储存在队列中的订单,防止重复提交,在真实场景中,可用redis代替 验证重复
*/
Map cacheMap = new ConcurrentHashMap<>();
/**
* 订单的缓冲队列,当线程池满了,则将订单存入到此缓冲队列
*/
Queue TestController 类
package com.springboot.demo;
import com.springboot.demo.Threads.TestThreadPoolManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.Queue;
import java.util.UUID;
/**
* Created by Administrator on 2018/5/9.
*/
@RestController
public class TestController {
@Autowired
TestThreadPoolManager testThreadPoolManager;
/**
* 测试模拟下单请求 入口
* @param id
* @return
*/
@GetMapping("/start/{id}")
public String start(@PathVariable Long id) {
//模拟的随机数
String orderNo = System.currentTimeMillis() + UUID.randomUUID().toString();
testThreadPoolManager.addOrders(orderNo);
return "Test ThreadPoolExecutor start";
}
/**
* 停止服务
* @param id
* @return
*/
@GetMapping("/end/{id}")
public String end(@PathVariable Long id) {
testThreadPoolManager.shutdown();
Queue q = testThreadPoolManager.getMsgQueue();
System.out.println("关闭了线程服务,还有未处理的信息条数:" + q.size());
return "Test ThreadPoolExecutor start";
}
}
3.使用JMeter模拟并发下单请求

4.结果
打印的日志说明,开始的订单直接执行插入到系统,当线程池的容量已经满了,则使用RejectedExecutionHandler方法把后面的订单添加到 Queue缓冲队列,使用ScheduledFuture方法定时(我这里是每秒一次)检查Queue队列,重新把队列里面的订单添加到线程池,执行后面的插入任务。
部分日志如下

最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。
PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。
点“在看”支持小哈呀,谢谢啦😀
评论

