线程池

image.png

线程池基础

  • 请求队列 线程池维护一定数量的线程,当线程池在运行状态的线程数量达上限时,其他线程被放入各请求队列,排除等待线程池释放提供资源。

1. 线程池状态
  1. volatile int runState; //运行状态
  2. //当创建线程池后,初始时,线程池处于RUNNING状态
  3. static final int RUNNING = 0;
  4. //调用了shutdown()方法;此时等待池内和队列中所有线程执行完毕,不接受新任务
  5. static final int SHUTDOWN = 1;
  6. //调用了shutdownNow()方法; 此时尝试终止正在执行的任务,且拒绝接受新任务
  7. static final int STOP = 2;
  8. //shutdown或stop 且所有工作线程销毁,队列清空。
  9. static final int TERMINATED = 3;

2. 任务的执行
  1. private final BlockingQueue<Runnable> workQueue; //任务缓存队列,用来存放等待执行的任务
  2. private final ReentrantLock mainLock = new ReentrantLock(); //线程池的主要状态锁,对线程池状态(比如线程池大小、runState等)的改变都要使用这个锁
  3. private final HashSet<Worker> workers = new HashSet<Worker>(); //用来存放工作集
  4. private volatile long keepAliveTime; //线程存活时间
  5. private volatile boolean allowCoreThreadTimeOut; //是否允许为核心线程设置存活时间
  6. private volatile int corePoolSize; //核心池的大小(即线程池中的线程数目大于这个参数时,提交的任务会被放进任务缓存队列)
  7. private volatile int maximumPoolSize; //线程池最大能容忍的线程数
  8. private volatile int poolSize; //线程池中当前的线程数
  9. private volatile RejectedExecutionHandler handler; //任务拒绝策略
  10. private volatile ThreadFactory threadFactory; //线程工厂,用来创建线程
  11. private int largestPoolSize; //用来记录线程池中曾经出现过的最大线程数
  12. private long completedTaskCount; //用来记录已经执行完毕的任务个数

3. 线程池中的线程初始化
  1. prestartCoreThread():初始化一个核心线程;
  2. prestartAllCoreThreads():初始化所有核心线程

4. 任务缓存队列及排队策略
  1. //任务缓存队列,用来存放等待执行的任务
  2. private final BlockingQueue<Runnable> workQueue;

【排队策略】:

  • ArrayBlockingQueue : 基于数组的先进先出阻塞队列,必须指定数组大小
  • LinkedBlckingQueue: 基于链表 ,默认大小为Integer.MaxValue
  • synchronousQueue: 这个比较特殊,不会保存任务,直接创建线程执行任务。

5. 任务拒绝策略

image.png
【任务拒绝的前提】: 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize
【任务拒绝策略】:

  • ThreadPoolExecutor.AbortPolicy //丢弃任务并抛出RejectedExecutionException异常。
  • DiscardPolicy //丢弃任务,但不抛出异常
  • DiscardOldestPolicy //丢弃队列最前的任务,尝试重新执行任务
  • CallerRunsPolicy //由调用线程执行该任务

6. 线程池的关闭
  • shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
  • shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务

7. 线程池容量的动态调整

 ThreadPoolExecutor提供了动态调整线程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),

  • setCorePoolSize:设置核心池大小
  • setMaximumPoolSize:设置线程池最大能创建的线程数目大小

线程池最佳数量计算

并发下线程池的最佳数量计算

cpu核心数*2


实战

线程池 | 配置及持久化异常日志

参考资料

java线程池实现原理及其在美团项目中的应用