Java线程池

286 阅读4分钟

线程池(ThreadPoolExecutor)的继承实现结构

image.png

线程池的状态

ThreadPoolExecutor使用int的高3位来表示线程的状态,低29位来表示线程的数量。

image.png

这些信心存储在一个ctl原子变量中,目的是将线程状态和线程数合在一起,执行一次cas操作就可完成两个的赋值。 image.png

线程池的构造方法和参数

image.png

  • coorPoolSize:核心线程数
  • maxinumPoolSize:最大线程数
  • keepAliveTime:救急线程的生存时间
  • unit:时间单位,针对上一个参数
  • workQueue:阻塞队列
  • threadFactory:线程工厂
  • handler:拒绝策略

线程池的工作流程:

  • 线程池一开始并没有线程,当一个任务被提交后,线程池会创建一个线程去执行任务

  • 当多个任务被提交时,如果当前线程处于工作状态,无法及时处理任务,线程池会创建其他的线程去执行任务

  • 当线程池的线程数达到coorPoolSize时,当有新的任务被提交时,如果当前所有的线程都处于工作状态,那么线程池就会将新的任务加入到workQueue阻塞队列中

  • 如果后续不断地有任务被提交,加入到阻塞队列中,如果阻塞队列是有界的,当阻塞队列已满时,如果有新的任务有被提交进来,则这个时候会创建救急线程来执行任务,救急线程数最多为最大线程数maxinumPoolSize减去核心线程数coorPoolSize。

  • 当所有的救急线程都被创建,任务队列已满,这时仍有任务被提交,则会执行拒绝策略,JDK提供四四种拒绝策略的实现,不同的拒绝策略有不同的效果:

    • AbortPolicy:让调用者抛出RejectedExecutorException异常
    • CallerRunsPolicy:让调用者运行任务
    • DiscardPolicy:放弃本次任务
    • DisscardOldestPolicy:放弃队列中最早加入的任务,用本任务替换
  • 当任务高峰过去后,如果救急线程一段时间没有任务,就会被结束掉,这个时间由keepAliveTime和unit控制

线程池工工厂

JDK的Executors类中提供了多种线程池的工厂方法,不同的方法通过调用线程池构造方法时传的不同参数值,来返回具有不同特性的线程池。

1. newFixedThreadPool

image.png 固定线程数量的线程池,我们可以看到这里的构造方法传参数时,最大线程数等于核心线程数,意味着不会创建救急线程,所以这里救急线程的存活时间也是0,同时阻塞队列也是无界队列。

特点
  • 没有救急线程
  • 阻塞队列是无界队列,可以一直往里面加入任务 适用于任务量已知,执行时间较长的任务
2.newCachedThreadPool

image.png

带有缓冲的线程池,我们可以看到线程池的和线程数为0,而救急线程数则是Integer的最大值,救急线程空闲时存活的时间为60s,阻塞队列采用的是没有容量的阻塞队列。

特点:
  • 没有核心线程数,所有的线程都是救急线程,救急线程的空闲生存时间为60s
  • 使用了SynchronousQueue作为阻塞队列,没有容量,只有当线程来取任务的时候,任务才能放进去

适用于任务比较密集,但是单个任务执行时间较短的情况。

3.newSingleThreadPool

image.png

单线程的线程池,没有救急线程,阻塞队列是无界队列

4.newScheduledThreadPool

任务调度线程池,可以定时执行任务,也可以周期执行任务

定时执行任务:

image.png 周期执行任务:

image.png

image.png 注意:如果在执行上次任务时所花的时间大于间隔的周期,则在上个任务执行完毕后立即执行下次任务

image.png

特点
  • 使用了装饰器模式,之对外暴露特定的方法,可以避免某些核心方法被暴露,从而破坏单线程。
单线程线程池和自己创建线程的区别

自己创建的线程在出现异常时会终止执行,不会有补救措施,而单线程线程池在执行期间出现异常则会创建一个新的线程,保证后续任务的执行。

提交任务

线程池中定义了多种提交任务的方法:

image.png

image.png

关闭线程池

shutdown()

执行此方法发线程池的状态会变为SHUTDOWN,不会接受新的任务,但是已提交的任务会执行完,调用此方法不会阻塞线程的执行。

shutdownNow()

线程池状态变为STOP,会用interrupt中断正在执行的任务,不再接受新的任务,会返回阻塞队列中的任务。