详解线程池

线程池通过复用线程,避免线程频繁地创建和销毁。Java中的Executors工具类中提供了5种类型的线程池创建方法,如下图所示:


image.png

详解线程池参数

线程池都是通过ThreadPoolExecutor的不同初始化参数来创建的。
创建参数列表如下图所示。


image.png
  • 第一个参数设置核心线程数。默认情况下核心线程会一直存活。
  • 第二个参数设置最大线程数。决定线程池最多可以创建的线程数。
  • 第三个参数和第四个参数用来设置线程空闲时间,和空闲时间的单位,当线程闲置超过空闲时间就会被销毁。可以通过allowCoreThreadTimeOut方法来允许核心线程被回收。
  • 第五个参数设置缓冲队列,上图中左下方的三个队列是设置线程池时常用的缓存队列,其中ArrayBlockingQueue是一个有界队列,LinkedBlockingQueue是无界队列,最后一个是SycnronousQueue是一个同步队列,内部没有缓冲区。
  • 第六个参数设置线程池工厂方法,线程工厂用来创建新线程,可以用来对线程的一些属性进行定制。例如线程的group、线程名、优先级等。一般使用默认工厂类即可。
  • 第七个参数设置线程池满时的拒绝策略。Abort策略在线程池满后,提交新任务时会抛出RejectedExecutionException,这个也是默认的拒绝策略。Discard策略会在提交失败时对任务之间进行丢弃。CallerRuns策略会在提交失败时,由提交任务的线程直接执行提交的任务。DiscardOldest策略会丢弃最早提交的任务。

回头再看Java自带线程池是如何配置参数的。

  • newFixedThreadPool固定大小线程池创建时核心和最大线程数都设置成指定的线程数,这样线程池中就只会使用固定大小的线程数,使用LinkedBlockingQueue。
  • Single线程池就是线程数设置为1的固定线程池。
  • Cached 线程池的核心线程数设置为0,最大线程数是Integer.MAX_VALUE,主要是通过把缓冲队列设置成SynchronousQueue,这样只要没有空闲线程就会创建。
  • Scheduled线程池与前几种不同的是使用了DelayedWorkQueue,这是一种按延迟时间获取任务的优先级队列。

详解线程池执行流程

向线程提交任务时可以使用execute和submit,区别就是submit可以返回一个future对象,通过future对象可以了解任务执行情况,可以取消任务的执行,还可获取执行结果,submit最终也是通过execute执行。

image.png

向线程池提交任务时的执行顺序如上图所示。

  1. 向线程池提交任务时,会首先判断线程池中的线程数是否大于设置的核心线程数,如果不大于,就创建一个核心线程来执行任务。
  2. 如果大于核心线程数,就会判断缓存队列是否满了,如果没有满,则放入队列,等待线程空闲时执行任务。
    3.如果队列已经满了,则判断是否达到了线程池最大数,如果没有,则创建新的线程来执行任务。
  3. 如果已经达到了最大线程数,则执行指定的拒绝策略。

特别提示:这里需要注意队列的的判断与最大线程数判断的顺序,不要搞反。

你可能感兴趣的:(详解线程池)