一文带你深入了解线程池

太过爱你忘了你带给我的痛 2023-09-28 23:57 204阅读 0赞

目录

    • 一. 什么是线程池
    • 二. 为什么要使用线程池
    • 三. 线程池的参数
    • 四. 线程池的工作流程
    • 五. 使用Executors 创建常见的功能线程池

一. 什么是线程池

简单来说,线程池就是提前创建好一批线程,当有任务的时候,从池子中取出一个线程去执行该任务,执行结束后,再把线程放回池子中,以备循环使用。

二. 为什么要使用线程池

  1. 降低资源消耗,线程一个生命周期需要经过创建、调度、销毁过程,使用线程池,可以降低线程创建和销毁的消耗。
  2. 提高响应速度,当有任务分配过来时,可以直接调度,不需要创建线程,速度快。
  3. 提高可管理性,使用线程池可以对线程进行统一的分配、调优和监管。

三. 线程池的参数

以标准库的线程池为例,它的参数列表如下:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

下面对这些参数进行介绍:

corePoolSize:核心线程数,即常备线程数

maximumPoolSize:最大线程数,常备线程数 + 临时线程数

keepAliveTime:线程的空闲时间,简单来说,就是临时线程活干完的时候,不会直接销毁临时线程,而是会观察一段时间,如果没有其他任务,再进行销毁。

TimeUnit unit:时间单位,m、ms等。

workQueue:工作队列,没有临时线程时,任务太多,核心线程(常备线程)做不完,则把任务存储到工作队列中。

threadFactory:线程工厂,用来创建线程,一般使用默认的线程工厂就可以了。

handler:拒绝策略,任务太多了,工作队列满了,就会执行拒绝策略。

常见的拒绝策略:

在这里插入图片描述

ThreadPoolExecutor.AbortPolicy:拒绝任务,抛出异常(直接拒绝,和领导吵一架)。

ThreadPoolExecutor.CallerRunsPolicy:由调用者来执行该任务(拒绝任务,让领导去做)。

ThreadPoolExecutor.DiscardOldestPolicy:把新任务加入,丢弃最早的任务。

ThreadPoolExecutor.DiscardPolicy:直接拒绝,什么也不做。

四. 线程池的工作流程

  1. 线程池刚创建时,线程池是一个空的,没有任何线程。
  2. 随着任务的提交,线程池开始创建线程:
    a. if (当前线程数 < corePoolSize) ,创建线程
    b. if (当前线程数 == corePoolSize) ,则把任务添加到工作队列中去
    c. 队列满了,if (当前线程数 < maximumPoolSize) ,创建线程(此时创建的为临时线程)
    d. 队列满了,if (当前线程数 == maximumPoolSize) ,执行拒绝策略
  3. 随着任务的执行,任务逐渐减少,线程有了空闲时间,则:
    if(空闲时间 > keepAliveTime && 当前线程数 > corePoolSize),则销毁线程,直到 当前线程数 == corePoolSize。

五. 使用Executors 创建常见的功能线程池

Executors为我们封装好了 4 种常见的功能线程池如下:

  1. 定长线程:FixedThreadPool
  2. 定时线程:ScheduledThreadPool
  3. 可缓存线程池:CachedThreadPool
  4. 单线程化线程池:SingleThreadExecutor

使用 Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池,该方法创建的线程池的返回值类型均为 ExecutorService。

定长线程:FixedThreadPool
源码:

  1. public static ExecutorService newFixedThreadPool(int nThreads) {
  2. return new ThreadPoolExecutor(nThreads, nThreads,
  3. 0L, TimeUnit.MILLISECONDS,
  4. new LinkedBlockingQueue<Runnable>());
  5. }
  6. public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
  7. return new ThreadPoolExecutor(nThreads, nThreads,
  8. 0L, TimeUnit.MILLISECONDS,
  9. new LinkedBlockingQueue<Runnable>(),
  10. threadFactory);
  11. }

特点:定长线程池 核心线程数 == 最大线程数 ,即没有临时线程,且执行完毕会立刻回收,这种类型的线程池使用频率最高。

定时线程:ScheduledThreadPool
源码:

  1. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
  2. return new ScheduledThreadPoolExecutor(corePoolSize);
  3. }
  4. public ScheduledThreadPoolExecutor(int corePoolSize) {
  5. super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
  6. new DelayedWorkQueue());
  7. }
  8. public static ScheduledExecutorService newScheduledThreadPool(
  9. int corePoolSize, ThreadFactory threadFactory) {
  10. return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
  11. }
  12. **加粗样式** **加粗样式** public ScheduledThreadPoolExecutor(int corePoolSize,
  13. ThreadFactory threadFactory) {
  14. super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
  15. new DelayedWorkQueue(), threadFactory);
  16. }

特点:定时线程池的核心线程数量固定,虽然它的构造方法里面没有写最大线程的数量是多少,但是跟进查看源码可以知道,最大线程数量是等于 Integer.MAX_VALUE 的,工作队列是高度定制化的延迟阻塞队列DelayedWorkQueue,其实现原理和DelayQueue基本一样,核心数据结构是二叉最小堆的优先队列,队列满时会自动扩容,所以offer操作永远不会阻塞,maximumPoolSize也就用不上了,所以线程池中永远会保持至多有corePoolSize个工作线程正在运行。

可缓存线程池:CachedThreadPool
源码:

  1. public static ExecutorService newCachedThreadPool() {
  2. return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
  3. 60L, TimeUnit.SECONDS,
  4. new SynchronousQueue<Runnable>());
  5. }
  6. public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
  7. return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
  8. 60L, TimeUnit.SECONDS,
  9. new SynchronousQueue<Runnable>(),
  10. threadFactory);
  11. }

特点:可缓存线程池的核心线程数 = 0,最大线程数为 Integer.MAX_VALUE ,它会在执行闲置60s后回收,任务队列为不储存元素的阻塞队列。适合于并发不固定的短期的小任务。

单线程化线程池:SingleThreadExecutor
源码:

  1. public static ExecutorService newSingleThreadExecutor() {
  2. return new FinalizableDelegatedExecutorService
  3. (new ThreadPoolExecutor(1, 1,
  4. 0L, TimeUnit.MILLISECONDS,
  5. new LinkedBlockingQueue<Runnable>()));
  6. }
  7. public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
  8. return new FinalizableDelegatedExecutorService
  9. (new ThreadPoolExecutor(1, 1,
  10. 0L, TimeUnit.MILLISECONDS,
  11. new LinkedBlockingQueue<Runnable>(),
  12. threadFactory));
  13. }

特点:单线程化线程池的核心线程数 == 最大线程数 == 1,执行完毕会立即回收,任务队列为链表结构的有界队列。

发表评论

表情:
评论列表 (有 0 条评论,204人围观)

还没有评论,来说两句吧...

相关阅读