java线程池ThreadPoolExecutor的keepAliveTime=0时,表示超过core线程数的线程在空闲时立即结束!!!

本文深入探讨了Java线程池中keepAliveTime参数的作用,特别是针对核心线程和非核心线程的不同行为。通过代码测试验证了当keepAliveTime设置为0时,核心线程不会被回收,而非核心线程会在空闲时被终止。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天同事突然提出问题说用哪个线程池好,newFixedThreadPool和newCacheThreadPool里选择,说固定大小线程池keepAliveTime=0,线程空闲会立马回收线程从而节约资源,然后另外一个同事说,0是代表永远不回收,我记忆里也是记得0是永久存活,因为网上很多博客啊,资料啊都是说的0表示线程永久存活在空闲的时候。前面那位同事也是从字面上认为的,没有经过验证,觉得-1才是永久不回收,然后各自进行了一波研究分析。

经过看源码,发现keepAliveTime<0是不行的,直接报错,也就是同事的猜测-1才是不回收 是错误的,看下面代码图示(别问我怎么给代码里部分标红,直接用浏览器F12自己编辑页面写标签样式进去的。。)

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

然后找keepAliveTime的使用一时半会也没找到,就用代码测试了,发现设置keepAliveTime=0核心线程数确实没有回收,后面同事说在并发病程的艺术那本书上有一段描述

当线程池中的线程数大于corePoolSize时,keepAliveTime为多余的空闲线程等待新任务的 最长时间,超过这个时间后多余的线程将被终止。这里把keepAliveTime设置为0L,意味着多余 的空闲线程会被立即终止。

同事又开始迷茫了,我一开始没细看,觉得说的不对,后面反复阅读,发现这段文字描述的是说keepAliveTime控制的是非核心线程数的回收,也就是0的时候,非核心线程数会在空闲的时候回收,并不是说核心的会回收。

为了验证结果,我们就用代码进行了测试,测试代码如下:

package com.xhs.concurrent.threaddemo.sync;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author xuhan  build  2019/4/23
 */
public class ExecutorsDemo implements Runnable{

    private int i=0;

    public ExecutorsDemo(int i) {
        this.i = i;
    }
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1,2,0, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(1));
        for(int i=0;i<3;i++){
            executor.execute(new ExecutorsDemo(i));
        }
        while(true){
            System.out.println("总线程数:"+executor.getPoolSize()+"当前活跃线程数:"+executor.getActiveCount());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void run() {
        System.out.println("i="+i+" Thread = "+Thread.currentThread().getName());
        if(i>=1){
            try {
                TimeUnit.SECONDS.sleep(1);
                System.out.println("i="+i+" sleep 1 s结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println("i="+i+" sleep 3 s结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

设置核心线程数和非核心线程数分别为1个,队列容量为1,进入3个runnable:

第一个创建主线程,第二个进入队列,第三个则创建非主线程运行,

输出结果为

  • i=0 Thread = pool-1-thread-1
  • i=2 Thread = pool-1-thread-2
  • 总线程数:2当前活跃线程数:2
  • 总线程数:2当前活跃线程数:2
  • i=2 sleep 1 s结束
  • i=1 Thread = pool-1-thread-2
  • 总线程数:2当前活跃线程数:2
  • 总线程数:2当前活跃线程数:2
  • i=1 sleep 1 s结束
  • 总线程数:1当前活跃线程数:1
  • 总线程数:1当前活跃线程数:1
  • i=0 sleep 3 s结束
  • 总线程数:1当前活跃线程数:0

可以看到非核心数线程执行完毕之后,队列中的task进入继续执行,等再次进入队列的task结束后,可以看到总线程数减少了1,而等核心线程执行完毕后,发现总线程数没有减少,但活跃线程数减少,也就是核心线程数没有回收。书上说的是正确的,大部分网上的博客说的keepAliveTime=0永久不回收是有出入的。

如果要设置核心线程的回收,则需要设置

executor.allowCoreThreadTimeOut(true);

但这是keepAliveTime必须要>0才行,否则会抛出异常!!!

throw new IllegalArgumentException("Core threads must have nonzero keep alive times");

如果看了之后觉得有问题,希望各位指点一番!!谢谢!!

 


 

 

 

<think>用户问的是Java线程池的核心线程数在运行过程中能否修改。我需要先回忆一下线程池的相关知识。 首先,线程池的核心线程数是由创建线程池设置的参数决定的,比如通过ThreadPoolExecutor的构造函数或者执行器服务的方法。核心线程数决定了线程池中保持活动的最小线程数量,即使它们处于空闲状态。 接下来,用户想知道在运行过程中是否可以修改这个核心线程数。根据我的记忆,ThreadPoolExecutor类提供了setCorePoolSize方法,这个方法允许在运行动态调整核心线程数。所以答案应该是可以修改的。 不过,我需要确认一下这个方法的实现细节。当调用setCorePoolSize线程池会如何调整?比如,如果新的核心线程数比当前活动的线程数大,线程池会创建新的线程吗?或者如果新的核心线程数更小,线程池会终止多余的线程吗? 根据Java文档,当核心线程数增加线程池可能会创建新的线程来满足新的核心数,但不会立即创建,而是在提交新任务才会创建。而当核心线程数减少,如果当前活动线程数超过新的核心数,多余的线程会在空闲一段间后(由keepAliveTime控制)被终止。 另外,还需要注意,修改核心线程数可能会影响线程池的性能,尤其是在高并发场景下。突然增加核心线程数可能导致资源竞争,而减少核心线程数可能导致任务排队间增加。 用户可能是在实际开发中遇到了需要动态调整线程池参数的情况,比如根据系统负载动态调整核心线程数以优化资源使用。这候,了解如何正确使用setCorePoolSize方法就很重要了。 最后,总结一下:Java线程池的核心线程数在运行过程中可以通过setCorePoolSize方法修改,但修改后的效果可能不会立即显现,而是根据线程池的当前状态和任务提交情况逐步调整。</think>在 Java 中,线程池的核心线程数core pool size)**可以在运行过程中动态修改**。这是通过 `ThreadPoolExecutor` 类提供的 `setCorePoolSize(int corePoolSize)` 方法实现的。以下是具体说明: ### 1. 修改方式 通过调用 `executor.setCorePoolSize(newCoreSize)` 即可调整核心线程数。例如: ```java ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5); executor.setCorePoolSize(10); // 将核心线程数调整为 10 ``` ### 2. 修改后的行为 - **若新核心数 > 当前活动线程数**:线程池不会立即创建新线程,但后续提交的任务会触发新线程的创建,直到活动线程数达到新核心数。 - **若新核心数 < 当前活动线程数**:多余的线程不会立即终止,而是会在空闲超过 `keepAliveTime` 后被回收(前提是 `allowCoreThreadTimeOut` 设置为 `true`;默认情况下,核心线程不会因空闲被终止)。 ### 3. 注意事项 - **动态调整的适用场景**:适合根据系统负载动态优化线程池资源,例如在低负载减少核心线程数以节省资源,高负载增加核心线程数以提升任务处理能力。 - **与 `allowCoreThreadTimeOut` 的配合**:若希望核心线程空闲被终止,需同设置 `executor.allowCoreThreadTimeOut(true)`,否则核心线程会一直存活(即使数量超过新核心数)。 ### 总结 Java 线程池的核心线程数支持运行动态修改,通过 `setCorePoolSize` 方法实现,但修改后的效果会结合线程池的当前状态和任务提交情况逐步生效。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值