修复线程池超过最大数量

举例

烧烤店吃烧烤。

  • 店内10个桌(corePoolSize),店外5个桌,这个店最多同时吃10个桌(maximumPoolSize)
  • 店外城管不让占道,所以店内10个桌满了,先排队 (BlockingQueue)
    • 这队长度,有的理论最大值 Integer.MAX_VALUE,几乎没限制
    • 有的有限制 bounded
    • 有的店员就拉一个人,还拉着不让你走,一有桌子,立马让你上桌
  • 队都满了,那就店外开桌 (5桌)
  • 店外都超5桌了,那就看店家啥策略了 (RejectedExecutionHandler)
    • 有的直接砸店,不干了 (AbortPolicy,这不是傻瓜嘛)
    • 有的让最早排队的滚蛋,老人等的不耐烦了 (DiscardOldestPolicy)
    • 有的让最晚排队的滚蛋,新人不想等 (DiscardPolicy)
    • 有的就让你现在站着吃,不用入桌子了 (CallerRunsPolicy 哈哈哈哈哈哈)
  • 这店外的桌子,得尽快收拾,过段时间 (keepAliveTime)都没人入座,就把店外桌子收起来。
  • 店内默认不收桌子,你要允许收 (allowCoreThreadTimeOut),那过段时间(keepAliveTime)没人做,也把桌子收起来

修复方法

1. 修改 reject 策略

提交的task超出 线程池最大限制(maximumPoolSize + queued tasks size 池子里的最大数+进池子最长排队数),就会触发 reject 策略。默认策略为 AbortPolicy (抛出异常),

  • reject策略 继承自:RejectedExecutionHandler
  • 换成其他子类:
    • DiscardOldestPolicy (抛弃 task等待执行队列中 最早加入的task),除非Executor被shutdown,那就不执行了
    • DiscardPolicy 抛弃当前的task
    • CallerRunsPolicy 执行execute的线程运行,不异步了。除非Executor被shutdown,那就不执行了
    • AbortPolicy 抛出异常

2. 扩大允许线程最大 数量

最大并发数就是:maximumPoolSize + queued tasks size = 25个

  • 扩大maximumPoolSize数
  • 扩大 queued 的capacity(容量)
    • 比如采用 LinkedBlockingDeque, capacity 是 Integer.MAX_VALUE
      • LinkedBlockingDeque 不直接创建队列,
    • 如果用了ArrayBlockingQueue,会直接创建 最大数数组,会消耗资源,不推荐这个设置最大值
    • SynchronousQueue 的容量是0(为什么是0)

文档

看下文档,thread pool 属性: corePoolSize核心线程数、maximumPoolSize 最大线程数、BlockingQueue阻塞队列、RejectedExecutionHandler抛弃线程策略、keepAliveTime

当提交新 task时

  • 优先创建核心线程: 现有线程 < corePoolSiz, 创建新线程
    • 核心线程不被回收,除非 allowCoreThreadTimeOut ,则超出 keepAliveTime 后被回收。
  • 优先队列排队:corePoolSize < 现有线程数
  • 队列满了,则创建新线程
    • task执行完,thread变空闲,超出 keepAliveTime 时间则回收线程
  • 线程数大于maximumPoolSize,启动RejectedExecutionHandler,默认实现类为 AbortPolicy,抛出异常

测试代码

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Description:
 * 

* Create by zhaojialiang02 2022/9/23 2:09 下午 */ public class TestThread { final static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 4, 15, 200, TimeUnit.MINUTES, new ArrayBlockingQueue(10)); public static void main(String[] args) { final int count = 40; for (int j = 0; j<3; j++) { final int jParam = j; threadPoolExecutor.execute(new Runnable() { @Override public void run() { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("End first thread group: " + jParam); } }); } try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("First wake up"); for (int i = 0; i < count; i++) { System.out.println("1Generate thread:" + i); final int index = i; threadPoolExecutor.execute(new Runnable() { @Override public void run() { System.out.println("++++++Start thread:" + index); try { Thread.sleep(1000 * 60 * 60); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("------End thread:" + index); } }); } try { Thread.sleep(1000 * 60 * 5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("------App GG"); } }

创建线程池的API

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

报错信息

///.....
++++++Start thread:23
1Generate thread:25
++++++Start thread:24
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task TestThread$2@74a14482 rejected from java.util.concurrent.ThreadPoolExecutor@1540e19d[Running, pool size = 15, active threads = 15, queued tasks = 10, completed tasks = 3]
        at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
        at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
        at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
        at TestThread.main(TestThread.java:49)

Running, pool size = 15, active threads = 15, queued tasks = 10, completed tasks = 3

你可能感兴趣的:(java,java)