线程池七个参数

线程池在Java中通常由 java.util.concurrent.ThreadPoolExecutor 类实现,其主要参数包括:

  1. corePoolSize(核心线程数)
  2. maximumPoolSize(最大线程数)
  3. keepAliveTime(空闲线程存活时间)
  4. unit(存活时间单位)
  5. workQueue(任务队列)
  6. threadFactory(线程工厂)
  7. handler(拒绝策略)

这些参数的配置需要根据具体的应用场景来调整(可以搭配属性配置文件进行动态配置)。以下是根据不同实际场景的一些配置建议:

1. corePoolSize(核心线程数)

含义:线程池中的常驻核心线程数,即使线程池中没有任务,这些线程也不会被销毁。

配置建议

  • CPU密集型任务(例如大量的计算任务):核心线程数通常设置为CPU核心数(例如,如果有8个CPU核心,corePoolSize可以设置为8或8+1)。
  • I/O密集型任务(例如网络请求、文件读写等):核心线程数可以设置为CPU核心数的2倍或更多,因为I/O操作可能会阻塞线程。

2. maximumPoolSize(最大线程数)

含义:线程池中能够容纳的最大线程数。

配置建议

  • CPU密集型任务:通常设置为核心线程数的2-4倍。例如,如果corePoolSize设置为8,maximumPoolSize可以设置为16-32。
  • I/O密集型任务:可以设置为更大的值,例如核心线程数的3-4倍,以处理更多的并发任务。

3. keepAliveTime(空闲线程存活时间)

含义:当线程数超过核心线程数时,多余的线程的空闲时间,超过这个时间多余的线程将被销毁。

配置建议

  • 长时间任务处理:可以设置较长的keepAliveTime,例如60秒或更多,以防止频繁创建和销毁线程。
  • 短时间任务处理:可以设置较短的keepAliveTime,例如10-30秒,以避免长时间占用资源。

4. unit(存活时间单位)

含义:keepAliveTime的时间单位。

配置建议:一般选择秒(TimeUnit.SECONDS)或毫秒(TimeUnit.MILLISECONDS)作为单位,具体取决于keepAliveTime的值。例如,TimeUnit.SECONDS 是最常用的单位。

5. workQueue(任务队列)

含义:用于保存等待执行任务的队列。

配置建议

  • 无界队列(如 LinkedBlockingQueue):适合任务提交速度快但处理速度较慢的情况,避免任务丢失。
  • 有界队列(如 ArrayBlockingQueue):适合对资源有严格控制的场景,可以避免内存过度消耗。
  • 同步队列(如 SynchronousQueue):适合任务提交和处理速度几乎一致的情况,可以使线程池更紧凑,但不支持缓存任务。

6. threadFactory(线程工厂)

含义:用于创建线程池中工作线程的工厂。

配置建议

  • 使用默认的线程工厂或自定义工厂。自定义线程工厂可以用来设置线程的名称、优先级和线程组,以便于调试和管理。

7. handler(拒绝策略)

含义:当任务队列满了且工作线程数达到最大线程数时,线程池会执行拒绝策略来处理新提交的任务。

配置建议

  • AbortPolicy:默认策略,直接抛出 RejectedExecutionException 异常,适用于不能容忍任务丢失的情况。
  • CallerRunsPolicy:将任务回退给调用者线程处理,适用于需要控制任务量而不是丢弃任务的情况。
  • DiscardPolicy:丢弃新提交的任务,适用于允许丢弃任务而不影响系统稳定性的情况。
  • DiscardOldestPolicy:丢弃队列中最旧的任务,然后尝试执行新任务,适用于允许丢弃旧任务而执行新任务的情况。

示例配置

假设你有一个需要处理大量I/O密集型任务的系统,以下是一个可能的线程池配置:

/**
     *  在实际业务中,thread Runnable Callable启动线程都不用,
     *                          将所有的多线程异步任务都交给线程池执行-资源控制
     *                          
     * public ThreadPoolExecutor(int corePoolSize,
     *                               int maximumPoolSize,
     *                               long keepAliveTime,
     *                               TimeUnit unit,
     *                               BlockingQueue<Runnable> workQueue,
     *                               ThreadFactory threadFactory,
     *                               RejectedExecutionHandler handler)
     *
     * 七大参数:
     *  corePoolSize:核心线程数【一直存在除非设置( allowCoreThreadTimeOut)】
     *                               线程池,创建好以后就准备就绪的线程数量,就等待来接受异步任务去执行
     *  maximumPoolSize:【200】最大线程数量,控制资源
     *  keepAliveTime:存活时间。如果当前的线程数量大于core数量
     *                      释放空闲的线程(maximumPoolSize-corePoolSize)。只要线程空闲大于指定的keepAliveTime就释放
     *  TimeUnit:时间单位
     *  BlockingQueue:阻塞队列,用来存储等待执行的任务,如果当前对线程的需求超过了 corePoolSize
     *                       大小,就会放在这里等待空闲线程执行。
     * ThreadFactory:创建线程的工厂,比如指定线程名等
     * RejectedExecutionHandler:拒绝策略,如果线程满了,线程池就会使用拒绝策略。
     *
     *  工作顺序:
     *  运行流程:
     * 1、线程池创建,准备好 core 数量的核心线程,准备接受任务
     * 2、新的任务进来,用 core 准备好的空闲线程执行。
     * (1) 、core 满了,就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队
     * 列获取任务执行
     * (2) 、阻塞队列满了,就直接开新线程执行,最大只能开到 max 指定的数量
     * (3) 、max 都执行好了。Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自
     * 动销毁。最终保持到 core 大小
     * (4) 、如果线程数开到了 max 的数量,还有新任务进来,就会使用 reject 指定的拒绝策
     * 略进行处理
     * 3、所有的线程创建都是由指定的 factory 创建的。
     *
     *      new LinkedBlockingDeque<>(100000) 默认是Integer的最大值。内存不够 / 业务需求
     *
     *     面试:
     * 一个线程池 core 7; max 20 ,queue:50,100 并发进来怎么分配的;
     *        先有 7 个能直接得到执行,接下来 50 个进入队列排队,在多开 13 个继续执行。现在 70 个
     *   被安排上了。剩下 30 个默认拒绝策略。
     *   如果不想抛弃还要执行:使用CallerRunsPolicy策略
     *          public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {//同步执行线程的run方法
     *             if (!e.isShutdown()) {
     *                 r.run();
     *             }
     *
     * @param args
     */
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    10, // corePoolSize
    20, // maximumPoolSize
    60, // keepAliveTime
    TimeUnit.SECONDS, // unit
    new LinkedBlockingQueue<>(100), // workQueue
    new ThreadFactory() { // threadFactory
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setName("CustomThreadPoolThread");
            return t;
        }
    },
    new ThreadPoolExecutor.CallerRunsPolicy() // handler
);

总结

线程池的参数配置应根据具体的应用场景、负载特性和系统资源来调整。通过监控系统性能和任务执行情况,可以动态调整这些参数,以优化线程池的性能和资源使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值