ThreadPoolExecutor中活跃的线程数超过corePoolSize后新来的请求会进入阻塞队列

本文深入解析了Java线程池的核心参数corePoolSize和maximumPoolSize的作用机制,通过实例代码展示了当线程池内的活跃线程数超过corePoolSize时,新任务如何被放入队列,并在队列满时如何创建新线程直至达到maximumPoolSize。最后介绍了当线程池无法接受更多任务时的处理策略。

关于该类的文档 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html

描述中有以下内容

Core and maximum pool sizes

............. When a new task is submitted in method execute(java.lang.Runnable), and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full.

当方法execute(java.lang.Runnable)中提交新任务并且运行的线程少于corePoolSize时,即使其他工作线程处于空闲状态,也会创建一个新线程来处理该请求。如果运行的线程数于介corePoolSizemaxi与mumPoolSize之间,则只有在队列已满时才会创建新线程。

Queuing

Any BlockingQueue may be used to transfer and hold submitted tasks. The use of this queue interacts with pool sizing:

  • If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
  • If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
  • If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.

加粗部分意思: 如果线程池里的线程数大于corePoolSize,Executor会将新来的请求放进队列而不是增加一个新线程。

 

下面编写代码来证明:

public class ThreadPoolTest {

    public static void main(String[] args) {

       try {
           createThreadDemo();
       } catch (RejectedExecutionException e) {
           e.printStackTrace();
           System.exit(-1);
       }

    }

    private static void createThreadDemo() throws RejectedExecutionException {

        // 等待队列
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(6);

        // 创建线程池, 核心线程数为5, 最大线程数为10
        ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 10, 600, TimeUnit.SECONDS, workQueue);

        for (int i = 1; i < Integer.MAX_VALUE; i++) {

            pool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                    try {
                        Thread.sleep(300000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });

            System.out.println("创建第" + i + "个线程后, 线程池情况:" + pool.toString());
        }
    }

}

输出:

pool-1-thread-1

创建第1个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]

pool-1-thread-2

创建第2个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]

pool-1-thread-3

创建第3个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]

pool-1-thread-4

创建第4个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]

pool-1-thread-5

创建第5个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]

创建第6个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]

创建第7个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 5, active threads = 5, queued tasks = 2, completed tasks = 0]

创建第8个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0]

创建第9个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 5, active threads = 5, queued tasks = 4, completed tasks = 0]

创建第10个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]

创建第11个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 5, active threads = 5, queued tasks = 6, completed tasks = 0]

pool-1-thread-6

创建第12个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 6, active threads = 6, queued tasks = 6, completed tasks = 0]

pool-1-thread-7

创建第13个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 7, active threads = 7, queued tasks = 6, completed tasks = 0]

pool-1-thread-8

创建第14个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 8, active threads = 8, queued tasks = 6, completed tasks = 0]

pool-1-thread-9

创建第15个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 9, active threads = 9, queued tasks = 6, completed tasks = 0]

pool-1-thread-10

创建第16个线程后, 线程池情况:java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 10, active threads = 10, queued tasks = 6, completed tasks = 0]

Disconnected from the target VM, address: '127.0.0.1:52079', transport: 'socket'

java.util.concurrent.RejectedExecutionException: Task utils.ThreadPoolTest$1@563da1dc rejected from java.util.concurrent.ThreadPoolExecutor@78457235[Running, pool size = 10, active threads = 10, queued tasks = 6, completed tasks = 0]

at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048)

at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)

at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)

at utils.ThreadPoolTest.createThreadDemo(ThreadPoolTest.java:32)

at utils.ThreadPoolTest.main(ThreadPoolTest.java:15)

我们创建了一个corePoolSize为5、maximumPoolSize为10的线程池。 由结果得知, 当线程池内活跃的线程数大于5时,再来新的创建请求会直接进入队列(队列数往上增),直接到达队列的界限(这里是6)后, 再来新的请求时pool size会一直增大直到达到maximumPoolSize为止。 

结论: 线程池内活跃的线程数大于corePoolSize时, 新来的任务会先进队列, 如果队列满时会继续新建线程直到池内线程数达到maximumPoolSize为止。 这时如果再请求新的任务, 会执行设定的策略, 默认是直接拒绝创建。

 

 

 

 

线程池核心线程释放主要与线程空闲时间超过`keepAliveTime`有关,但在核心线程释放过程中,并不存在阻塞队列和最大线程数“执行顺序”的说法。不过在任务提交时,线程池处理任务有一定顺序,可借此理解它们的关系。 当调用`execute(Runnable task)`方法提交任务时,线程池处理顺序如下: 1. 检查线程池中当前运行的线程数是否小于`corePoolSize`,若小于,则创建的工作线程执行任务,即便有空闲工作线程[^1]。 2. 若线程数达到`corePoolSize`,提交任务放入`workQueue`(阻塞队列)排队等待[^1]。 3. 若`workQueue`已满,且线程池中的线程数量小于`maximumPoolSize`,继续创建线程执行任务[^1]。 4. 若线程数量达到`maximumPoolSize`,且`workQueue`已满,无法添加任务,根据指定的`RejectedExecutionHandler`策略处理该任务,如抛出异常或直接丢弃任务[^1]。 当线程池中的线程数超过`corePoolSize`,某线程空闲时间超过`keepAliveTime`,该线程会被终止以减少资源消耗,但只要线程数量大于等于`corePoolSize`,线程不会因空闲被终止[^1]。 总结来说,是先尝试将任务放入阻塞队列,当阻塞队列满后才考虑创建线程直至达到最大线程数。 ```java import java.util.concurrent.*; public class ThreadPoolExample { public static void main(String[] args) { int corePoolSize = 2; int maximumPoolSize = 4; long keepAliveTime = 1000; BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2); RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, workQueue, handler ); // 提交任务 for (int i = 0; i < 6; i++) { final int taskId = i; executor.execute(() -> { System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }); } executor.shutdown(); } } ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值