线程池的预热、线程池中核心线程的回收

2,505 阅读2分钟

众所周知,线程的创建和销毁都需要一定的开销。在日常开发中,应对换挡高峰,我们可能会采用线程池来并行的执行任务,来解决流量激增。线程池会成为开发人员最常用的工具。

线程池被创建后里面有线程吗?如果没有的话,你知道有什么方法对线程池进行预热吗?

线程池的类里面已经为我们封装好了方法:

启动所有的核心线程:

prestartAllCoreThreads()

image.png

仅启动一个核心线程:

prestartCoreThread()

image.png

线程池的预热仅仅针对核心线程,使用方法也会因为场景不用有所不同,大家按需选择,无需千篇一律。

核心线程数会被回收吗?需要什么设置?

核心线程数默认是不会被回收的,如果需要回收核心线程数,需要调用下面的方法:allowCoreThreadTimeOut 该值默认为 false。设置为true就会回收核心线程

  • allowCoreThreadTimeOut 该值默认为 false。

image.png

具体是会调用 interruptIdleWorkers 这个方法

image.png

这里需要讲一下的是 w.tryLock() 这个方法,可能会奇怪,Worker 怎么还能 lock。Worker 是属于工作线程的封装类,它不仅实现了 Runnable 接口,还继承了 AQS。

image.png

之所以要继承 AQS 就是为了用上 lock 的状态,执行任务的时候上锁,任务执行完了之后解锁,这样执行关闭线程池等操作的时候可以通过 tryLock 来判断此时线程是否在干活,如果 tryLock 成功说明此时线程是空闲的,可以安全的回收。

interruptIdleWorkers 对应的还有一个 interruptWorkers 方法,从名字就能看出差别,不空闲的 worker 也直接给打断了。

根据这两个方法,又可以扯到 shutdown 和 shutdownNow,就是关闭线程池的方法,一个是安全的关闭线程池,会等待任务都执行完毕,一个是粗暴的直接咔嚓了所有线程,管你在不在运行,两个方法分别调用的就是 interruptIdleWorkers() 和 interruptWorkers() 来中断线程。

image.png

这又可以引申出一个问题,shutdownNow 了之后还在任务队列中的任务咋办?线程池还算负责,把未执行的任务拖拽到了一个列表中然后返回,至于怎么处理,就交给调用者了!

详细就是上面的 drainQueue 方法。

image.png

都 drainTo 了,为什么还要判断一下队列是否为空,然后进行循环?

那是因为如果队列是 DelayQueue 或任何其他类型的队列,其中 poll 或 drainTo 可能无法删除某些元素,所以需要遍历,逐个删除它们。