【面试题】那你再说说线程池的核心配置参数都是干什么的?平时我们应该怎么用?

ThreadPoolExecutor(int corePoolSize, // 1
                int maximumPoolSize,  // 2
                long keepAliveTime,  // 3
                TimeUnit unit,  // 4
                BlockingQueue<Runnable> workQueue, // 5
                ThreadFactory threadFactory,  // 6
                RejectedExecutionHandler handler )

【corePoolSize】核心线程数,没达到核心线程数时,会创建新的线程。当达到核心线程数时,任务会进去队列

【maximumPoolSize】最大线程数,可以为Integer.MAX_VALUE 21亿。当达到核心线程数时,会去创建额外的线程来执行任务,最多不超过最大线程数

【keepAliveTime】存活时间,当任务处理完成,额外的线程存活一段时间后,会自行销毁。空闲等待时间(该参数默认对核心线程无效,当allowCoreThreadTimeOut手动设置为true时,核心线程超过存活时间后才会被销毁)

【TimeUnit】空闲等待时间的单位

【queue】利用什么队列来存放任务,有界队列、无界队列等。BlockingQueue为无界队列

【ThreadFactory】线程创建工厂

【RejectExecutionHandler】拒绝策略

 

假设把queue做成有界队列,如下new ArrayBlockingQueue<Runnable>(200),那么假设corePoolSize个线程都在繁忙的工作,大量的任务进入有界队列,队伍也满了,此时怎么办?

如果maximumPoolSize最大线程数比corePoolSize核心线程数大,会额外创建新的线程放入线程池中,用于处理队列中的任务。这些额外的线程处理完一个任务后,会尝试从队列中获取新的任务继续执行

如果额外的线程用完了,而且也在繁忙中,队列也是满的。这个时候还有新任务怎么办?

通过拒绝策略将任务拒绝掉,有几种拒绝策略,可以传入RejectExecutionHandler

(1)AbortPolicy

(2)DiscardPolicy

(3)DiscardOldestPolicy

(4)CallRunsPolicy

(5)自定义拒绝策略

一般比较常用的是fixedThreadPool。可根据上述原理去定制自己的线程池,考虑到核心线程数、队列类型、最大线程数、拒绝策略以及线程释放时间。

 

 

public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }

corePoolSize与maximumPoolSize相等,即其线程全为核心线程,是一个固定大小的线程池,是其优势;

keepAliveTime = 0 该参数默认对核心线程无效,而FixedThreadPool全部为核心线程;

workQueue 为LinkedBlockingQueue(无界阻塞队列),队列最大值Integer.MAX_VALUE。如果任务提交速度持续大余任务处理速度,会造成队列大量阻塞。因为队列很大,很有可能在拒绝策略前,内存溢出。是其劣势;

FixedThreadPool的任务执行是无序的;

引用:线程池之ThreadPoolExecutor使用

【评论区】

1、在实际的使用中,应该如何合理配置核心线程数和队列长度呢?

线程池数量取决于业务逻辑,计算密集型还是io密集型,队列长度取决于队列中每个对象的大小,32位的系统和64位的采取指针压缩的系统的每个对象的大小也是不一样的,然后根据你jvm的启动参数,推算得出

2、如果corePoolSize大于maximunPoolSize,最多创建的线程数以哪个为准?

抛异常,throw new IllegalArgumentException();

3、线程池能创建多个吗,我们生产中有许多任务是单独创建线程池?

完全可以 ,ThreadPoolExecutor 是 new 出来的,不是单例的

4、如果线程池使用newFixedThreadPool创建,如果阻塞队列使用的是无界队列的话,那么永远不会新建额外线程处理任务,那么额外线程岂不是没用了? 为何要有这种设计呢? 而且这种方式容易导致任务堆积,造成OOM,岂不是很危险,那么为什么不直接使用有界队列和指定数量的最大线程数这种方式,一次解决这些隐患呢?

这个要考虑具体的使用场景,有写场景下不允许拒绝丢弃任务,这时候就只能等线程池的线程慢慢的去消化队列里面的任务。如果场景允许丢弃任务那丢弃完全没问题

corePoolsize和maxmunPoolSize的意思,核心池的数量如果等于最大线程池那就是只用核心池了,最大线程池的数量包括核心池的数量呢,在ThreadPoolExecutor类的构造方法中,如果maximumPoolSize < corePoolSize的话,会抛出IllegalArgumentException异常,工厂类的线程池方法,maxmunPoolSize如果是Integer.MAX_VALUE的话,核心池的数量一般是0,来一个任务创建一个线程,IO密集型的任务才会用到这个,至于具体的创建线程池,建议最好采用构造方法手动创建,并指定有界队列

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值