解决方式:使用线程池+队列

项目基于Spring,如果不用spring需要自己把

ThreadPoolManager.java

改成单例模式

1.写一个Controller(Spring mvc)

/*** @author HeyS1* @date 2016/12/1* @description*/
@Controller
public class ThreadPoolController {@AutowiredThreadPoolManager tpm;@RequestMapping("/pool")public@ResponseBody Object test() { for (int i = 0; i < 500; i++) {   //模拟并发500条记录 tpm.processOrders(Integer.toString(i)); } return "ok"; } }

2.线程池管理

/*** @author HeyS1* @date 2016/12/1* @description threadPool订单线程池, 处理订单* scheduler 调度线程池 用于处理订单线程池由于超出线程范围和队列容量而不能处理的订单*/
@Component public class ThreadPoolManager implements BeanFactoryAware { private static Logger log = LoggerFactory.getLogger(ThreadPoolManager.class); private BeanFactory factory;//用于从IOC里取对象 // 线程池维护线程的最少数量 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; // 消息缓冲队列 Queue<Object> msgQueue = new LinkedList<Object>(); //用于储存在队列中的订单,防止重复提交 Map<String, Object> cacheMap = new ConcurrentHashMap<>(); //由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序 final RejectedExecutionHandler handler = new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { //System.out.println("太忙了,把该订单交给调度线程池逐一处理" + ((DBThread) r).getMsg()); msgQueue.offer(((DBThread) r).getMsg()); } }; // 订单线程池 final ThreadPoolExecutor threadPool = new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new ArrayBlockingQueue(WORK_QUEUE_SIZE), this.handler); // 调度线程池。此线程池支持定时以及周期性执行任务的需求。 final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5); // 访问消息缓存的调度线程,每秒执行一次 // 查看是否有待定请求,如果有,则创建一个新的AccessDBThread,并添加到线程池中 final ScheduledFuture taskHandler = scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { if (!msgQueue.isEmpty()) { if (threadPool.getQueue().size() < WORK_QUEUE_SIZE) { System.out.print("调度:"); String orderId = (String) msgQueue.poll(); DBThread accessDBThread = (DBThread) factory.getBean("dBThread"); accessDBThread.setMsg(orderId); threadPool.execute(accessDBThread); } // while (msgQueue.peek() != null) { // } } } }, 0, 1, TimeUnit.SECONDS); //终止订单线程池+调度线程池 public void shutdown() { //true表示如果定时任务在执行,立即中止,false则等待任务结束后再停止 System.out.println(taskHandler.cancel(false)); scheduler.shutdown(); threadPool.shutdown(); } public Queue<Object> getMsgQueue() { return msgQueue; } //将任务加入订单线程池 public void processOrders(String orderId) { if (cacheMap.get(orderId) == null) { cacheMap.put(orderId,new Object()); DBThread accessDBThread = (DBThread) factory.getBean("dBThread"); accessDBThread.setMsg(orderId); threadPool.execute(accessDBThread); } } //BeanFactoryAware @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { factory = beanFactory; } }

3.线程池中工作的线程

//线程池中工作的线程
@Component
@Scope("prototype")//spring 多例 public class DBThread implements Runnable { private String msg; private Logger log = LoggerFactory.getLogger(DBThread.class); @Autowired SystemLogService systemLogService; @Override public void run() { //模拟在数据库插入数据 Systemlog systemlog = new Systemlog(); systemlog.setTime(new Date()); systemlog.setLogdescribe(msg); //systemLogService.insert(systemlog); log.info("insert->" + msg); } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }

浏览器输入地址127.0.0.1/pool

几秒后关闭tomcat。

模拟500条数据,订单线程池处理了117条。调度线程池处理5条

关闭tomcat,后还有378条未处理(这里的实现需要用到spring监听器)。加起来一共500

OK。完毕

spring监听器,监听tomcat关闭事件:

public class MyApplicationListener implements ApplicationListener<ApplicationEvent> { @Autowired ThreadPoolManager threadPoolManager; @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ContextClosedEvent) { XmlWebApplicationContext x = (XmlWebApplicationContext) event.getSource(); //防止执行两次。root application context 没有parent,他就是老大 if (x.getDisplayName().equals("Root WebApplicationContext")) { threadPoolManager.shutdown(); Queue q = threadPoolManager.getMsgQueue(); System.out.println("关闭了服务器,还有未处理的信息条数:" + q.size()); } } else if (event instanceof ContextRefreshedEvent) { // System.out.println(event.getClass().getSimpleName()+" 事件已发生!"); } else if (event instanceof ContextStartedEvent) { // System.out.println(event.getClass().getSimpleName()+" 事件已发生!"); } else if (event instanceof ContextStoppedEvent) { // System.out.println(event.getClass().getSimpleName()+" 事件已发生!"); } else { // System.out.println("有其它事件发生:"+event.getClass().getName()); } } }

spring配置一下

<bean id="springStartListener" class="com.temp.MyApplicationListener"></bean>

转载于:https://www.cnblogs.com/vianzhang/p/8920445.html

javaWeb 使用线程池+队列解决订单并发问题相关推荐

  1. java redis队列_redis队列实现高并发怎么用?Java如何使用redis队列解决高并发?

    小伙伴们大家好,不知道你们有没有在Java开发中遇到redis队列高并发,这个问题让你很头疼,今天小编就来讲解一下在Java中遇到redis队列高并发了,到底该怎么办. 高并发的业务场景: 我们做商品 ...

  2. python盘点订单_django解决订单并发问题【推荐】

    并发处理 在多个用户同时发起对同一个商品的下单请求时,先查询商品库存,再修改商品库存,会出现资源竞争问题,导致库存的最终结果出现异常. 解决办法: 悲观锁 当查询某条记录时,即让数据库为该记录加锁,锁 ...

  3. 基于Django的乐观锁与悲观锁解决订单并发问题的一点浅见

    订单并发这个问题我想大家都是有一定认识的,这里我说一下我的一些浅见,我会尽可能的让大家了解如何解决这类问题. 在解释如何解决订单并发问题之前,需要先了解一下什么是数据库的事务.(我用的是mysql数据 ...

  4. 记一次线上压测Dubbo线程池队列满的问题

    本文记录一次线上全链路压测出现的Dubbo线程池队列满的问题. 1 问题描述 线上做全链路压测,其中涉及三个系统,调用关系A->B->C,均是dubbo调用.压测的时候C出现CPU满导致服 ...

  5. java线程优先级队列等待_java线程池队列优先级(插队)Demo

    在做线程池操作的时候,突然来个加紧处理时,会很纠结,不知道怎么处理让加紧的线程插队先执行.该Demo使用了自定义线程池,采用优先级阻塞式队列(PriorityBlockingQueue)的方式来处理插 ...

  6. mongodb线程池_常用高并发网络线程模型设计及MongoDB线程模型优化实践

    服务端通常需要支持高并发业务访问,如何设计优秀的服务端网络IO工作线程/进程模型对业务的高并发访问需求起着至关重要的核心作用. 本文总结了了不同场景下的多种网络IO线程/进程模型,并给出了各种模型的优 ...

  7. 500并发相当于多少人_linux开发技术之线程池accept处理高并发connect(含源码)

    前言 服务器在调用listen和accept后,就会阻塞在accept函数上,accpet函数返回后循环调用accept函数等待客户的TCP连接. 我们知道服务器段listen套接字能处理的连接数与监 ...

  8. Linux下套接字详解(七)----线程池accept处理高并发connect

    前言 服务器在调用listen和accept后,就会阻塞在accept函数上,accpet函数返回后循环调用accept函数等待客户的TCP连接. 我们知道服务器段listen套接字能处理的连接数与监 ...

  9. day14 线程池、原子性、并发工具类

    目录 一.线程池 1.1 线程状态 1.2 线程池的基本原理 1.3 Executors默认线程池 1.4 创建指定上限的线程池 1.5 ThreadPoolExecutor(线程池执行器) 1.5. ...

最新文章

  1. bzoj 4695: 最假女选手
  2. 逻辑心理测试题:三囚分汤
  3. 计算机网络:socket
  4. 十天学会AngularJS之02
  5. JVM性能调优实践:G1 垃圾收集器介绍篇
  6. 布线问题分支限界法java_大型布线:Java云应用程序缺少的技术
  7. Intro OpenCL Tutorial
  8. 第3关:HDFS-JAVA接口之上传文件
  9. QA:mongoose中设置virtual后不工作问题
  10. 【黑马程序员济南】我的“黑马”经历
  11. java拼音_Java获取汉字对应的拼音(全拼或首字母)
  12. 微信可以修改微信号了
  13. 医保结余7600亿匮
  14. css拉伸动画,CSS3 matrix双板划水、拉伸、打板动画实例animation
  15. 2018年人均寿命是多少_那是2018年
  16. 问号在c语言里面的作用,问号的作用是什么-写作基础知识
  17. 我说CMMI2.0之:策划PLAN
  18. 欧拉角和四元数之间转换公式推导
  19. D L N A介 绍
  20. windows安装.Net Framework3.5无法安装问题

热门文章

  1. 怎么在电脑上隐藏便签 win10系统怎么操作
  2. 2020安徽省程序设计大赛_收集圣物
  3. 大数据 / 大屏数据展示模板
  4. 求两个相交的线性函数的交点的Python程序
  5. 工业级远距离无线传输装置的功能有哪些?
  6. 软链接与硬链接 详细讲解
  7. Android 自动化集成打包平台搭建之Jkens详解
  8. eclipse-spark开发环境
  9. mos管选型之耗散功率
  10. MyBatis框架的基本搭建