java,使用ThreadPoolExecutor来手动创建线程池

线程池参数详解
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.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

七大参数


从源码中可以看出,线程池的构造函数有7个参数,分别是corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。下面会对这7个参数一一解释。
一、corePoolSize 线程池核心线程大小
        线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会 被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。
二、maximumPoolSize 线程池最大线程数量
        一个任务被提交到线程池后,首先会缓存到工作队列(后面会介绍)中,如果工作队列满了,则会创建一个新线程,然后从工作队列中的取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize来指定。
三、keepAliveTime 空闲线程存活时间
        一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定
四、unit 空间线程存活时间单位
        keepAliveTime的计量单位
五、workQueue 工作队列
        新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列:
        ①ArrayBlockingQueue
        基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。
        ②LinkedBlockingQuene
        基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。
        ③SynchronousQuene
        一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。
        ④PriorityBlockingQueue
        具有优先级的无界阻塞队列,优先级通过参数Comparator实现。
六、threadFactory 线程工厂
        创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等
七、handler 拒绝策略
        当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,jdk中提供了4中拒绝策略:
new ThreadPoolExecutor.AbortPolicy() // 不执行新任务,直接抛出异常,提示线程池已满
new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!由调用线程处理该任务
new ThreadPoolExecutor.DiscardPolicy() //不执行新任务,也不抛出异常
new ThreadPoolExecutor.DiscardOldestPolicy() //丢弃队列最前面的任务,然后重新提交被拒绝的任务。


 

<think>好的,用户想知道Java手动创建线程池的好处与优势。首先,我需要回顾一下线程池的基本概念以及为什么需要手动创建而不是使用内置的。 线程池的主要目的是减少线程创建和销毁的开销,提高系统性能。Java提供了Executors工具类来快速创建线程池,比如newFixedThreadPool、newCachedThreadPool等。但根据阿里开发手册,推荐手动创建ThreadPoolExecutor,这可能是因为Executors的预设配置存在一些问题,比如newFixedThreadPool使用无界队列可能导致内存溢出,而newCachedThreadPool可能创建过多线程导致资源耗尽。 手动创建线程池的好处应该包括更灵活的参数配置,比如核心线程数、最大线程数、队列类型及容量,还有自定义拒绝策略。这样可以更好地控制资源使用,避免OOM等问题。另外,手动创建允许根据具体业务需求调整线程池行为,比如设置线程存活时间、自定义线程工厂等,这些在Executors的工厂方法中是做不到的。 需要确认用户是否了解线程池的基本参数和原理,可能需要在回答中简要说明这些参数的作用。同时,引用中的资料提到线程池的优势在于透明和可控,手动创建可以避免预设实现的一些缺陷,比如newCachedThreadPool可能无限制增加线程的问题。 可能还需要提到资源管理的优化,手动配置队列大小和拒绝策略可以防止任务堆积,提升系统稳定性。此外,线程池的监控和调优也是手动创建的优势,比如通过扩展ThreadPoolExecutor的方法来监控任务执行情况。 要确保回答结构清晰,分点列出优势,并结合引用内容说明。比如引用[2]提到ThreadPoolExecutor的参数控制,引用[1]比较了手动创建线程线程池的资源管理差异,引用[3]则提到线程创建的复杂性,但线程池可以简化这部分。 总结起来,手动创建线程池的优势包括:参数可控、避免资源耗尽、自定义拒绝策略、更好的资源管理、支持监控和扩展。需要将这些点用简洁的中文表达,并适当引用资料支持。</think>### Java 手动创建线程池的优势分析 在 Java 中,手动创建线程池(通过`ThreadPoolExecutor`类)相比直接使用`Executors`工具类提供的预设线程池,具有以下核心优势: --- #### 1. **参数灵活可控,避免资源耗尽风险** `ThreadPoolExecutor`允许开发者自定义以下关键参数: - **核心线程数(corePoolSize)**:长期存活的线程数量。 - **最大线程数(maximumPoolSize)**:线程池能容纳的最大线程数。 - **任务队列类型及容量(workQueue)**:例如有界队列`ArrayBlockingQueue`,可防止无界队列导致的内存溢出。 - **线程存活时间(keepAliveTime)**:非核心线程的空闲回收时间。 - **拒绝策略(RejectedExecutionHandler)**:当任务超过队列容量时,自定义处理逻辑(如丢弃、重试或记录日志)。 通过精细控制这些参数,可以避免`Executors`预设线程池的潜在问题。例如: - `Executors.newCachedThreadPool()`使用无容量队列,可能导致线程数激增,耗尽 CPU 和内存资源[^2]。 - `Executors.newFixedThreadPool()`使用无界队列,任务堆积时可能引发内存溢出(OOM)。 --- #### 2. **自定义拒绝策略,提升系统健壮性** 手动创建线程池时,可指定以下拒绝策略(或自定义实现): - **AbortPolicy**(默认):直接抛出异常,强制开发者处理任务过载问题。 - **CallerRunsPolicy**:由提交任务的线程执行任务,降低提交速度。 - **DiscardOldestPolicy**:丢弃队列中最旧的任务,腾出空间。 - **DiscardPolicy**:静默丢弃新任务。 例如,在电商秒杀场景中,可以通过自定义拒绝策略记录超限任务并异步重试,避免服务崩溃。 --- #### 3. **资源管理与性能优化** - **减少线程创建开销**:复用线程池中的线程,避免频繁创建和销毁线程的系统资源消耗[^1]。 - **控制并发量**:通过最大线程数限制,防止高并发场景下线程竞争导致的性能下降。 - **任务队列隔离**:针对不同业务类型创建独立线程池,避免相互影响(如订单处理与日志记录分离)。 --- #### 4. **支持监控与扩展** 通过继承`ThreadPoolExecutor`并重写其方法(如`beforeExecute`、`afterExecute`),可以实现: - **任务执行时间统计** - **线程池负载监控** - **异常捕获与告警** 例如: ```java public class CustomThreadPool extends ThreadPoolExecutor { @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); // 记录任务执行完成时间或异常 } } ``` --- ### 总结 手动创建线程池的优势主要在于**精细化资源控制**和**风险规避**,尤其适用于高并发、高可靠性的系统场景。相比之下,`Executors`的预设线程池更适合简单的测试或低并发需求,但在生产环境中需谨慎使用[^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值