SynchronousQueue的不恰当使用,瞬时过载导致线程池任务被拒绝

设计实现是要求在服务启动时,创建一批常驻线程,从阻塞队列里取元素执行业务逻辑。为此我刚开始使用的代码如下:
使用CommandLineRunner在服务启动时创建好线程

public class ConflictFactory implements CommandLineRunner{

  private static final int CD_EXECUTOR_THREAD = Runtime.getRuntime().availableProcessors();

  private static final ThreadPoolExecutor CD_EXECUTOR = new ThreadPoolExecutor(
														  CD_EXECUTOR_THREAD, 
														  CD_EXECUTOR_THREAD, 
														  0L,
														  TimeUnit.MILLISECONDS, 
														  new SynchronousQueue<>(), 
														  new NamedThreadFactory("CD-", false),
														  new ThreadPoolExecutor.AbortPolicy());

  static {
     CD_EXECUTOR.prestartAllCoreThreads();
  }

  @Override
  public void run(String... args) throws Exception {
      for (int i = 0; i < CD_EXECUTOR_THREAD; i++) {
          CD_EXECUTOR.execute(() -> {
              while (true) {
                  try {
                      node = singleDomainQueue.take();
                      、、、、、、
                  } catch (Exception e) {
                      、、、、、、
                  }
              }
          });
      }
   }
}

运行时偶发报错,提示任务被拒绝
在这里插入图片描述
创建的任务数量=核心线程数量为什么 任务还会被拒绝呢?

虽然使用了prestartAllCoreThreads()预先创建线程,但是当任务提交时,线程还未全部创建完毕,active threads = 1,还未达到CD_EXECUTOR_THREAD个。由于SynchronousQueue的特性 :

  • 不会存储任务,必须由 某个线程立即消费,否则任务会被拒绝。
  • 线程的创建、任务提交、任务执行 必须完全同步,否则任务会失败

瞬时过载导致任务被拒绝。

还是老老实实换成了LinkedBlockingQueue,暂存一下任务,等线程逐步创建完成再执行。

  private static final ThreadPoolExecutor CD_EXECUTOR = new ThreadPoolExecutor(
													  CD_EXECUTOR_THREAD, 
													  CD_EXECUTOR_THREAD, 
													  0L,
													  TimeUnit.MILLISECONDS, 
													  new LinkedBlockingQueue<>(CD_EXECUTOR_THREAD + 3), 
													  new NamedThreadFactory("CD-", false),
													  new ThreadPoolExecutor.AbortPolicy());

SynchronousQueue只适合任务数量<最大线程数量,并且线程已经是就绪状态的场景。高吞吐、低延迟,但适用于短时任务,线程池需要足够的线程数,否则任务会被拒绝

在这里插入图片描述


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值