【精简版八股】线程池笔记

107 阅读5分钟

线程池参数

  1. corePoolSize 线程池核心线程数
    • 线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。
  1. maximumPoolSize 线程池最大线程数量
    • 一个任务被提交到线程池以后,首先会找有没有空闲存活线程,如果有则直接将任务交给这个空闲线程来执行,如果没有则会缓存到工作队列(后面会介绍)中,如果工作队列满了,才会创建一个新线程,然后从工作队列的头部取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列尾部。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。
  1. keepAliveTime 空闲线程存活时间
    • 一个非核心线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定
  1. unit 空闲线程存活时间单位
    • keepAliveTime的计量单位
  1. workQueue 工作队列
    1. ArrayBlockingQueue

      1. 数组有界大小固定
      2. 基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。
    2. LinkedBlockingQuene

      1. 链表有界大小可变
      2. 基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。
    3. SynchronousQuene

      1. SynchronousQueue的capacity是0,该队列不存储任何元素
      2. 也就是说SynchronousQueue的每一次insert操作,必须阻塞到其他线程的remove操作。而每一个remove操作也必须阻塞其他线程的insert操作。
    4. PriorityBlockingQueue

      1. 具有优先级的无界阻塞队列,优先级通过参数Comparator实现。
    5. 队列管理任务方法

抛出异常特殊值阻塞超时
插入[add(e)][offer(e)][put(e)][offer(e, time, unit)]
移除[remove()][poll()][take()][poll(time, unit)])
检查[element()][peek()]不可用不可用

handler 拒绝策略

  1. CallerRunsPolicy
    • 该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。
  1. AbortPolicy
    • 该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。
  1. DiscardPolicy
    • 该策略下,直接丢弃任务,什么都不做。
  1. DiscardOldestPolicy
    • 该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

线程池核心线程数为0任务怎么创建

  1. 当核心线程数为0的时候,会创建一个非核心线程进行执行

  2. 核心线程数不为0的时候,如果核心线程数在执行,会有一个非核心线程数从队列中取对象执行线程

  3. 核心线程数执行的是队列的take,非核心线程数执行队列的offer和poll

  4. 核心线程数不为0且队列为SynchronousQueue时,就成了单线程运行了

线程池一个任务从被提交到被执行,线程池做了哪些工作?

  1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行他们。
  2. 当调用execute()方法添加一个任务时,线程池会做如下判断:
    1. 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务
    2. 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列
    3. 如果这时候队列满了,而且正在运行的线程数量小于maximunPoolSize,那么还是要创建非核心线程立刻运行这个任务
    4. 如果队列满了,而且正在运行的线程数量大于或等于maximunPoolSize,那么线程池会抛出RejectedExecutionException
  1. 当一个线程完成任务时,它会从队列中取下一个任务来执行

  2. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到corePoolSize的大小

常见线程池有哪些

  1. newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
  4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。