这些关于线程池相关的高频面试题你都知道吗

1、java 线程池的核心属性有哪些,其含义是什么?

JAVA 线程池的核心属性如下:

  • int corePoolSize
    核心线程数
  • int maximumPoolSize
    线程池最大线程数
  • long keepAliveTime
    线程保持活跃的时间
  • TimeUnit unit
    keepAliveTime 的时间单位
  • BlockingQueue< Runnable > workQueue
    任务挤压队列
  • ThreadFactory threadFactory
    线程创建工厂类
  • RejectedExecutionHandler handler
    拒绝策略

2、向线程池提交任务时线程创建过程?

那当用户向线程池提交一个任务的时候,线程池会如何创建线程呢?

  1. 首先线程池会判断当前已创建的线程是否小于 corePoolSize (核心线程数),如果小于,则无论已创建的线程是否空闲,都会选择创建一个新的线程来执行该任务,直到已创建的线程等于核心线程数

  2. 当线程池中已创建的线程数等于核心核心线程数时,用户继续向线程池提交任务时,此时会先判断任务队列是否已满:
    1)如果任务队列未满,则将任务放入队列中。
    2)如果任务队列已满,则判断当前线程数量是否超过了最大线程数量,如果未超过,则创建一个新的线程来执行该任务,如果线程池已创建的线程数量等最大线程数,则执行拒绝策略。

所以如果线程池使用的队列无界队列,最大线程数会变的没有意义。

3、线程池的拒绝策略有哪些,其使用场景分别是什么?

JUC 默认提供了如下拒绝策略:

  • AbortPolicy
    拒绝,直接抛出 RejectedExecutionException,默认值。
  • CallerRunsPolicy
    由调用线程直接运行任务的 run 方法,即异步转同步。
  • DiscardOldestPolicy
    丢弃任务队列中最新进入
  • DiscardPolicy
    拒绝了,就不执行,“当没事人事”样。

拒绝策略触发的条件:线程池使用的是有界任务队列时,才有可能被触发,当队列已满,并且线程池创建的线程已经达到了最大允许的线程池时。

默认情况下,通常使用 AbortPolicy 即可

CallerRunsPolicy 异步转同步在出现拒绝的情况下其实意义不大,没有想出其合适的场景,因为需要执行拒绝策略的时候,已经处理变慢了,再同步执行任务,只会增加服务器的负载,不利于恢复问题。

DiscardOldestPolicy 这种策略,通常用于类似记录轨迹,偶尔丢失点数据没关系,但希望最新的数据能得到保存。

DiscardPolicy 策略,通常用来异步打印日志,直接忽略不执行,期望保存旧的数据。

4、如何选择阻塞队列

阿里内部的开源规范明确禁止使用无界队列,因为如果使用无界队列,任务会不受限制的往线程池中提交,有可能造成内存溢出。

如果使用无界队列,最大线程数这个参数将会失效,因为永远也不会创建多于核心线程数量的线程。

5、线程池工厂有和实际用处

ThreadFactory threadFactory,线程池工厂,在使用线程池时,强烈推荐使用自己定义的线程工厂,这样能为线程池中的线程进行命名,方便跟大家使用 jsatck 命令查看线程栈时,能快速识别对应的线程。

6、keepAliveTime参数的作用

keepAliveTime :通俗点来说,这个参数表示线程的最大空闲时间,即如果线程没有在执行任务,能存活的时间。

默认情况下,该参数只针对 超过 核心线程数(corePoolSize) 的线程

当然如果 allowCoreThreadTimeOut 设置为 ture ,则核心线程数也会因为空闲而被关闭。

那如何来设置 keepAliveTime 呢?

如果流量是一波一波的,不建议设置该值,考虑如下场景:

如果业务每隔 10分钟来一波流量洪峰,每一波处理3分钟,如果将 keepAliveTime 设置为 5分钟,为了节省资源,最小线程数设置为10,最大线程数设置100,这样一波流量过来,10个核心线程肯定处理不过来,马上创建线程,然后处理过后,创建的线程由于空闲,则相继关闭,然后又来一波流量,又创建,这样其实线程池的意义就不大了。

一般使用线程池,基本上我会将 corePoolSize 与 maxPoolSize 设置相等,同一个项目中,不同的业务,对应不同的线程池,实现线程隔离。

猜你喜欢

转载自blog.csdn.net/prestigeding/article/details/115190789