引言
并发量非常大,服务器处理不够及时导致消息堆积的问题是很常见的。上篇文章简单的描述演示了一种解决方案就是增加消费者,提高消息处理速度,使用的是AMQP提供的监听器工厂SimpleRabbitListenerContainerFactory,本篇文章演示另一种方式,在消费者中开启线程池加快消息处理速度。
线程池ThreadPoolExecutor
Java.util提供的ThreadPoolExecutor有七个核心参数
- corePoolSize 核心线程数
- maximumPoolSize 最大线程数=核心线程数+备用线程数
- keepAlivetime 备用线程的生存时间
- unit 备用线程的生存时间
- workWueue 阻塞队列
- threadFactory 线程工厂,定义线程对象的创建
- handler 拒绝策略 当最大线程数达到并且阻塞队列也满时,会触发拒绝策略。
线程池的种类有四种
固定线程数的线程池:newFixedThreadPool(int Threads)
特点:
- 核心线程数与最大线程数一样,不存在备用线程
- 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE
单线程化的线程池:newSingleThreadExecutor()
只使用为一的工作线程来执行任务,保证所有任务按照指定顺序执行FIFO
特点:
- 核心线程数和最大线程数都是1
- 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE
可缓存线程池:newCachedThreadPool()
特点:
- 核心线程数为0
- 最大线程数是Integer.MAX_VALUE
- 阻塞队列为SynchronousQueue:不存储元素的阻塞队列,每个插入操作都需要等待一个移出操作
具有延迟和周期性执行:newScheduledThreadPoolExecutor(int corePoolSize)
可以执行延迟任务,支持定时以及周期性操作。
环境配置(参考上篇文章)
定义线程池
使用Spring提供的ThreadPoolTaskExecutor
package cn.itcast.mq.thread; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.*; @Configuration @EnableAsync public class ThreadPoolConfig { /*定义线程池,提供多个线程消费消息 */ @Bean("pooltoconsumer") public ThreadPoolTaskExecutor pooltoconsumer() { // ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); threadPoolTaskExecutor.setCorePoolSize(8); threadPoolTaskExecutor.setMaxPoolSize(20); threadPoolTaskExecutor.setQueueCapacity(100); threadPoolTaskExecutor.setKeepAliveSeconds(3); threadPoolTaskExecutor.setThreadNamePrefix("开启多个线程消费消息----"); threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); threadPoolTaskExecutor.initialize(); return threadPoolTaskExecutor; } }
修改MQ监听器
@Async("pooltoconsumer")
@RabbitListener(bindings = @QueueBinding(value = @Queue(name="demo.queue2"),exchange = @Exchange(name = "direct",type = ExchangeTypes.DIRECT),key = {"川菜"}) )
public void chuancai(String msg)
{
//拆分消息
String[] split = msg.split(":");
order order = new order(split[0], split[1]);
System.out.println(order.toString());
//保存MYSQL
orderService.save(order);
//测试是否多个消费者
System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务" +"----"+"川菜"+"----"+split[1]);
}