一、前言
今天我在看why技术的时候,看到了这个。发现这个没有全部的八股回答?于是我就结合自己的经验,分享下八股
二、八股问答
2.1了解JDK Executors线程池吗?
Executor就是一个线程池框架,在开发中如果需要创建线程可优先考虑使用Executor,无论你需要多线程还是单线程,Executor为你提供了很多其他功能,包括线程状态,生命周期的管理。
Executor 位于
java.util.concurrent.Executors
,提供了用于创建工作线程的线程池的工厂方法。
2.2知道JDK提供了哪些默认的实现吗?
- FixedThreadPool(n):创建一个数量固定的线程池,超出的任务会在队列中等待空闲的线程,可用于控制程序的最大并发数。
- CachedThreadPool():短时间内处理大量工作的线程池,会根据任务数量产生对应的线程,并试图缓存线程以便重复使用,如果限制 60 秒没被使用,则会被移除缓存。
- SingleThreadExecutor():创建一个单线程线程池。
- ScheduledThreadPool(n):创建一个数量固定的线程池,支持执行定时性或周期性任务。
- SingleThreadScheduledExecutor():此线程池就是单线程的 newScheduledThreadPool。
- WorkStealingPool(n):Java 8 新增创建线程池的方法,创建时如果不设置任何参数,则以当前机器处理器个数作为线程个数,此线程池会并行处理任务,不能保证执行顺序。
2.3 看过阿里巴巴java开发手册吗?知道为啥不允许使用默认的实现吗?
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
2.4 你们没有用默认的吧?那来介绍一下你们自定义线程池的几个常用参数呗?
- corePoolSize 核心线程池的大小
- maximumPoolSize 最大线程池大小
- keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程超出有效时间也关闭
- TimeUnit keepAliveTime的时间单位
- workQueue阻塞任务队列
- threadFactory新建线程工厂
- RejectedExecutionHandler当提交任务数超过maximumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理
常规八股直接说
2.5 你这个几个参数的值是怎么得来的呀?算出来的?怎么算出来的?
CPu密集corePoolSize = cpu核数+1
IO密集型 corePoolSize = cpu核数*2
2.6 线程池里面的任务是I0密集型的还是计算密集型的呢?好,现在我们有一个自定义线程池了,来说一下你这个线程池的工作流程呗?
- 当线程池小于corePoolSize时,新提交的任务会创建一个新线程执行任务,即使线程池中仍有空闲线程。
- 当线程池达到corePoolSize时,新提交的任务将被放在workQueue中,等待线程池中的任务执行完毕
- 当workQueue满了,并且maximumPoolSize > corePoolSize时,新提交任务会创建新的线程执行任务
- 当提交任务数超过maximumPoolSize,新任务就交给RejectedExecutionHandler来处理当线程池中超过 corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
- 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
2.7 那你这个线程池满了怎么办呀?拒绝?咋拒绝?有哪些拒绝策略呢?
AbortPolicy
,也是ThreadPoolExecutor
的默认策略,在提交任务失败时直接抛出RejectedExecutionException
异常;CallerRunsPolicy
,在任务被拒绝添加至线程池后,会调用当前线程池所在的线程去执行被拒绝的任务,但其缺点是会阻塞主线程;DiscardOldestPolicy
,在任务被拒绝添加值线程池后,会抛弃最早加入到队列(workQueue
)的任务,再把这个新任务添加进去;DiscardPolicy
,在任务被拒绝添加至线程池后,任务会被直接丢弃,也不会抛出异常,是最不安全也不推荐的。
2.8 回到开始说的阿里巴巴java开发手册不允许使用默认实现,你回答说可能会引起OOM,那我们聊聊JVM吧