修复线程池超过最大数量

举例

烧烤店吃烧烤。

  • 店内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:
 * <p>
 * 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<Runnable> 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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值