线程详解之线程池ThreadPoolExecutor

Posted 攻城狮Chova

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程详解之线程池ThreadPoolExecutor相关的知识,希望对你有一定的参考价值。

ThreadPoolExecutor

基本概念

  • 一个ExecutorService执行每一个提交的任务,这些任务可以是线程池中的一个任务
  • 通常使用Executor工厂方法进行配置
  • 线程池解决了两个问题:
    • 可以在进行大量异步操作时改善性能,提供了一种绑定和资源管理的方式,通过控制一些参数达到优化每一个任务执行开销
    • 线程池中维护了一些统计信息,可以用来了解线程池的基本状态

ThreadPoolExecutor

public class ThreadPoolExecutor extends AbstractExecutorService

  • ThreadPoolExecutor继承AbstractExecutorService.AbstractExecutorService是一个抽象类,实现了ExecutorService接口 .ExecutorService是一个接口,继承Executor接口
  • Executor:
    • 顶层接口
    • 只声明了一个方法execute(Runnable), 参数类型为Runnable, 返回值为void. 用来执行传入的任务
  • ExecutorService:
    • 继承Executor接口
    • 声明了方法submit(), invokeAll(), invokeAny()shutDown() 方法等
  • AbstractExecutorService:
    • 实现ExecutorService接口
    • 基本实现ExecutorService中声明的所有方法
  • ThreadPoolExecutor:
    • 继承AbstractExecutorService
  • ThreadPoolExecutor中提供了许多参数和可扩展的钩子函数来应对不同场景中的线程池的创建
    • 默认情况下,所有线程包括核心线程都是在新任务到达时才被创建和启动.如果使用非空队列构造线程池,需要预启动线程可以使用prestartCoreThread或者prestartAllCoreThread
    • 新线程使用ThreadFactory创建,默认情况下,使用ExecutordefaultThreadFactory进行创建,所创建的线程都位于相同的线程组中,并且具有相同的优先级和非守护状态
    • 通过自定义ThreadFactory, 可以自定义线程的名称,线程组,优先级,守护进程状态等
    • 如果ThreadFactorynewThread返回null表示线程创建失败,执行程序可能继续执行,也可能出现异常,无法执行任何任务

ThreadPoolExecutor构造方法

  • ThreadPoolExecutor中有四个构造方法:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue);

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

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

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler);
  • ThreadPoolExecutor提供四个构造器,根据每个构造器的源码,可以发现,前三个构造器都是调用最后一个构造器进行初始化构造的
  • ThreadPoolExecutor构造方法中的参数:
    • corePoolSize: 核心线程池大小
    • maximumPoolSize: 线程池中的最大线程数
    • keepAliveTime: 线程没有执行任务时最多保持的指定时间后线程终止
    • unit: 时间参数的单位
    • workQueue: 缓存等待执行任务的阻塞队列
    • threadFactory: 创建线程的线程工厂
    • handler: 拒绝任务的处理策略

corePoolSize

  • corePoolSize: 核心线程池的大小
  • 默认情况下,线程池创建后,线程池中没有任何线程,等待有任务提交到线程池才会创建线程执行任务
  • 可以调用prestartAllCoreThreads() 方法或者prestartCoreThread() 方法预创建线程,在线程池创建后,没有任务提交到线程池之前就创建corePoolSize个线程或者一个线程
  • 默认情况下,线程池创建之后,线程池中的线程数为0, 有任务提交到线程池后,就会每次创建一个新的线程执行任务,当线程池中达到corePoolSize个线程后,就会将继续提交的任务存储到缓存队列workQueue中等待

maximumPoolSize

  • maximumPoolSize: 线程池中的最大线程数
  • 表示在线程池中最多可以创建maximumPoolSize个线程
  • corePoolSize和maximumPoolSize的使用:
    • 使用execute() 提交一个新的任务:
      • 运行中的线程小于corePoolSize时,即使其余的工作线程处于空闲状态,也会创建一个新的线程来处理新的任务
      • 如果运行的线程超过从corePoolSize但是小于maximumPoolSize时,那么只有在工作队列已满时才会创建新新线程
    • corePoolSizemaximumPoolSize设置为一个相同值时可以创建一个固定大小的线程池. 将maximumPoolSize设置为一个没有上限的值Integer.MAX_VALUE, 则允许线程池容纳任意数量的并发数量
    • corePoolSizemaximumPoolSize仅在构建时设置,也可以通过setCorePoolSizesetMaximumPoolSize动态修改

keepAliveTime

  • keepAliveTime: 线程没有执行任务时最多保持的指定时候后线程终止
  • keepAliveTime参数提供了一种在线程池中的工作线程没有使用时减少资源消耗的方法
    • 如果运行的线程超过corePoolSize, 并且空闲的线程的空闲时间超过了keepAliveTime时,那么多余的线程将会被终止
    • 如果线程池变得更加活跃时就会创建新的线程,默认情况下 ,keepAliveTime只会对于线程池运行的线程数多于corePoolSize的情况生效

unit

  • unit: 参数keepAliveTime的时间单位,包含以下7种取值:
    • TimeUnit.DAYS:
    • TimeUnit.HOURS: 小时
    • TimeUnit.MINUTES: 分钟
    • TimeUnit.SECONDS:
    • TimeUnit.MILLISECONDS: 毫秒
    • TimeUnit.MICROSECONDS: 微秒
    • TimeUnitNANOSECONDS: 纳秒

workQueue

  • workQueue: 一个阻塞等待队列. 用来缓存等待执行的任务
  • workQueue参数的选择会对线程池的运行过程产生重大的影响. 通常情况下,阻塞队列有4种选择:
    • LinkedBlockingQueue
    • SynchronousQueue
    • ArrayBlockingQueue
    • PriorityBlockingQueue
  • LinkedBlockingQueueSynchronousQueue使用较多 ,ArrayBlockingQueuePriorityQueue使用较少.线程的排队策略和BlockingQueue相关

threadFactory

  • threadFactory: 线程工厂,主要用来创建线程

handler

  • handler: 拒绝任务的策略. 有以下4种拒绝策略:
    • ThreadPoolExecutor.AbortPolicy: 丢弃任务并且抛出RejectedExecutionException异常
    • ThreadPoolExecutor.DiscardPolicy: 丢弃任务,但是不抛出异常
    • ThreadPoolExecutor.DiscardOldestPolicy: 丢弃队列中最前面的任务,然后重新尝试执行任务. 重复这样的过程操作
    • ThreadPoolExecutor.CallerRunsPolicy: 调用线程处理这个任务

ThreadPoolExecutor重要方法

execute()

  • execute() 方法是ThreadPoolExecutor中的核心方法
  • ThreadPoolExecutor中的execute() 方法是对Executor中声明的execute() 方法的具体实现
  • ThreadPoolExecutor中的execute() 方法可以向线程池中提交一个任务到线程池中执行

submit()

  • submit() 方法是在ExecutorService中声明的方法,在AbstractExecutorService中对submit() 方法进行具体的实现 .ThreadPoolExecutor中继承了AbstractExecutorService中的submit() 方法,没有对这个方法进行重写
  • ThreadPoolExecutor中使用submit() 方法也是向线程池中提交一个任务到线程池中
  • submit() 方法和execute() 方法相比较:
    • submit() 方法能够返回任务执行的结果
    • submit() 方法的实现也是通过调用execute() 方法,只是使用Future来获取任务的执行结果

shutdown()

  • shutdown() 方法是用来关闭线程池的

shutdownNow()

  • shutdownNow() 方法是用来关闭线程池的

ThreadPoolExecutor工作原理

线程池状态

  • ThreadPoolEXecutor中定义了五个static final修饰的变量表示线程池的各种状态
	private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

以上是关于线程详解之线程池ThreadPoolExecutor的主要内容,如果未能解决你的问题,请参考以下文章

线程池bing

Java多线程系列——线程池简介

线程详解之线程池ThreadPoolExecutor

线程详解之线程池ThreadPoolExecutor

线程详解之线程池ThreadPoolExecutor

Java高并发之线程池详解