线程池面试题(不定期更新)
深度解读 Java线程池设计思想及源码实现
java 线程池有哪些关键属性?
corePoolSize,maximumPoolSize,workQueue,keepAliveTime,rejectedExecutionHandler
-
corePoolSize 到maximumPoolSize之间的线程会被回收,当然 corePoolSize的线程也可以通过设置而得到回收(allowCoreThreadTimeOut(true))。
-
workQueue 用于存放任务,添加任务的时候,如果当前线程数超过了corePoolSize,那么往该队列中插入任务,线程池中的线程会负责到队列中拉取任务。
-
keepAliveTime用于设置空闲时间,如果线程数超出了 corePoolSize,并且有些线程的空闲时间超过了这个值,会执行关闭这些线程的操作
-
rejectedExecutionHandler 用于处理当线程池不能执行此任务时的情况,默认有抛出 RejectedExecutionException 异常、忽略任务、使用提交任务的线程来执行此任务和将队列中等待最久的任务删除,然后提交此任务这四种策略,默认为抛出异常。
说说线程池中的线程创建时机?
注意:如果将队列设置为无界队列,那么线程数达到 corePoolSize 后,其实线程数就不会再增长了。因为后面的任务直接往队列塞就行了,此时 maximumPoolSize 参数就没有什么意义。
-
如果当前线程数少于corePoolSize,那么提交任务的时候创建一个新的线程,并由这个线程执行这个任务;
-
如果当前线程数已经达到corePoolSize,那么将提交的任务添加到队列中,等待线程池中的线程去队列中取任务;
-
如果队列已满,那么创建新的线程来执行任务,需要保证池中的线程数不会超过maximumPoolSize,如果此时线程数超过了maximumPoolSize,那么执行拒绝策略。
任务执行过程中发生异常怎么处理?
- 如果某个任务执行出现异常,那么执行任务的线程会被关闭,而不是继续接收其他任务。然后会启动一个新的线程来代替它。
什么时候会执行拒绝策略?
- workers 的数量达到了 corePoolSize(任务此时需要进入任务队列),任务入队成功,与此同时线程池被关闭了,而且关闭线程池并没有将这个任务出队,那么执行拒绝策略。这里说的是非常边界的问题,入队和关闭线程池并发执行
- workers 的数量大于等于corePoolSize,将任务加入到任务队列,可是队列满了,任务入队失败,那么准备开启新的线程,可是线程数已经达到 maximumPoolSize,那么执行拒绝策略。
四种ExecutorService线程池
- newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
- newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
拒绝策略
- ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
- ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)。
- ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务。
-
corePoolSize
为线程池的基本大小。 -
maximumPoolSize
为线程池最大线程大小。 -
keepAliveTime
和unit
则是线程空闲后的存活时间。 -
workQueue
用于存放任务的阻塞队列。 -
handler
当队列和最大线程池都满了之后的饱和策略