ThreadPoolExecutor功能特性

简介: ThreadPoolExecutor功能特性
  1. 核心和最大线程大小

ThreadPoolExecutor会根据CorePoolSize和maximumPoolSize来自动调整线程池大小。当一个新任务到来且线程池的中线程数量小于corePoolSize且其他工作线程空闲时,ThreadPoolExecutor会创建一个新线程处理这个请求。
ThreadPoolExecutor只会在任务队列已经满了并且线程数量大于corePoolSize但是小于maximumPoolSize时才会新建线程处理新的请求。
通过将corePoolSize和maximumPoolSize可以得到一个固定线程大小的线程池。
通过将maximumPoolSize设置为一个很大的数字,比如:Integer.MAX_VALUE,并且把这种设置放到生产环境上,那么你可能晚上睡不着觉。
一般情况下,线程池的core和maximum大小是通过ThreadPoolExecutor的构造函数来设置的,但是也可以通过setCorePoolSize(int) 和setMaximumPoolSize来更改。

  1. 按需新建线程

新建ThreadPoolExecutor后,它并不会直接按照corePoolSize的数量新建线程,而是当提交任务后才会新建线程。
但是我们可以通过调用prestartCoreThread()或者prestartAllCoreThreads来启动线程。
只有你创建了一个有任务的队列时,你才可能想要预启动线程。

  1. 创建线程方式

线程池中创建线程会使用ThreadFactory。如果你在创建线程池时没有指定ThreadFactory,那么ThreadPoolExecturo会使用Executors.defaultThreadFactory()来创建普通优先级且非守护线程。
通过使用不通的ThreadFactory,你可以修改线程的名称,线程组,优先级和是否为守护进程。
如果ThreadFactory在创建线程时返回了一个null对象,那么ThreadPoolExecutor会继续执行,但是并不会执行任务。

  1. 保活时间

如果线程池当前的线程数量大于corePoolSize,并且这些大于corePoolSize的线程的空闲时间已经超过了keepAliveTime设置的时间,那么这些线程会被终止。
在线程池没有被使用时,这种方式可以减少对资源的消耗。
如果过一段时间线程池又被激活了,那么线程池会再次创建新的线程。
keeAliveTime可以通过调用setKeepAliveTime来动态修改。如果keepAliveTime使用Long.MAX_VALUE就意味着你不想终止空闲的线程。
默认情况下,保活策略只有当线程池的线程数量大于corePoolSize时才会生效,但是你可以通过调用allowCoreThreadTimeOut函数针对核心线程执行超时策略。

  1. 任务队列

只要是实现了BlockingQueue接口的队列都可以作为任务队列参数传递给线程池。线程池对于队列大小的使用:

  • 如果当前正在运行的线程大小小于corePoolSize,那么线程池会一直添加新的线程
  • 如果当前线程池线程大小达到或超过了corePoolSize的话,那么线程池会先将任务入队,而不是创建一个新的线程
  • 如果一个新任务无法入队,如果线程池大小没有超过了maximumPoolSize的话,那么线程池会创建一个新线程,否则新任务会直接执行拒绝策略

队列的常用策略:

  • 直接传递

提交新任务后,新任务需要立即执行。在这种场景下,你需要设置一个无上限的MaximumPoolSize。

  • 无界队列

使用一个无界的队列(例如:LinkedBlockingQueue)在核心线程都在忙的时候任务一直等待。因为使用无界队列时,新任务可以一直入队,那么线程池中处于运行状态的线程就不会超过corePoolSize设置的大小,这也就意味着在创建线程池时指定的的MaximumPoolSize不会起作用。无界队列可以用于web Server。

  • 有界队列

有界队列可以有效的防止资源耗尽,但是会有点难以调整和控制。需要权衡队列大小和最大线程大小:如果使用大队列和小的线程大小,那么会有减少使用CPU利用率、操作系统资源和上下文切换的开销,但是会导致吞吐量降低;如果任务频繁阻塞(比如:任务是IO密集型的),那么系统的调度时间可能多于任务的执行时间。;如果使用小队列和大的线程池,那么会有很多CPU的调度开销,这当然也会降低系统的吞吐量

  1. 任务拒绝策略

拒绝策略发生条件:

  • 线程池已经终止
  • 线程池运行线程已经达到maximum指定的大小且队列已满

预定义的的拒绝策略:

  • 默认拒绝策略:AbortPolicy

该拒绝策略是直接抛出一个运行时异常RejectedExecutionException。

  • CallerRunsPolicy

该拒绝策略是提交任务的线程执行该任务。

  • DiscardPolicy

该拒绝策略是将任务丢弃。

  • DiscardOldPolicy

该拒绝策略是将任务队列中第一个任务丢弃,并尝试将该任务重新入队。
自定义策略

  • 自定义拒绝策略只需要实现RejectedExecutionHandler接口实现void rejectedExecution(Runnable r,

ThreadPoolExecutor executor);这个函数即可。

  1. 回调函数

ThreadPoolExecutor提供了beforeExecute(Thread, Runnable)和afterExecute(Runnable, Throwable)方法,表示在每个任务执行前和每个任务执行后执行该函数。例如:可以重新初始化ThreadLocal线程局部变量,统计数据或添加日志。另外,terminated()函数可以被重新来执行在线程池完全终止后的一些特殊业务处理。
如果钩子后者回调方法抛出了异常,那么可能内部的工作线程可能已经失败了或已经终止了。

  1. 队列维护

线程池提供了getQueue()允许用户来监控和调试。基于其他目的调用getQueue()并不鼓励。ThreadPoolExectutor提供了两个方法:remove(Runnable)和purge()可以用于在大量任务被取消时协助回收存储。

  1. 线程池终止

如果线程池没有任务执行并且已经没有了驻留的线程时,那么线程池就自动停止了。基于这个特性,那么你想要保证最终未使用的线程池回收或者用户忘记了调用shutdown()函数,那么你可以通过设置合适的保活时间和0个核心线程或通过设置allowCoreThreadTimeOut(boolean),你可以将未使用的线程死亡。

目录
相关文章
|
29天前
|
安全 Java 调度
【C/C++ 线程池设计思路 】设计与实现支持优先级任务的C++线程池 简要介绍
【C/C++ 线程池设计思路 】设计与实现支持优先级任务的C++线程池 简要介绍
44 2
|
7月前
|
Java 调度
Java中synchronized:特性、使用、锁机制与策略简析
Java中synchronized:特性、使用、锁机制与策略简析
|
9月前
|
存储 安全 Java
Java 中的线程池:线程池的作用、组成部分、使用方法、最佳实践
Java 中的线程池:线程池的作用、组成部分、使用方法、最佳实践
355 0
Java面试必问之线程池的创建使用、线程池的核心参数、线程池的底层工作原理
Java面试必问之线程池的创建使用、线程池的核心参数、线程池的底层工作原理
135 0
Java面试必问之线程池的创建使用、线程池的核心参数、线程池的底层工作原理
|
存储 Java 调度
【多线程:线程池】ThreadPoolExecutor类的基本概念
【多线程:线程池】ThreadPoolExecutor类的基本概念
118 0
|
存储 Java 程序员
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(下)
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(下)
|
算法 Java 应用服务中间件
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(上)
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(上)
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(上)
Juc05_线程池概述、创建方式、七大参数、底层工作原理、拒绝策略(三)
③. 你在工作中是如何创建线程池的,是否自定义过线程池使用 ④. 合理配置线程池你是如何考虑的?
114 0
Juc05_线程池概述、创建方式、七大参数、底层工作原理、拒绝策略(三)
Juc05_线程池概述、创建方式、七大参数、底层工作原理、拒绝策略(二)
③. 线程池的底层工作原理? ④. 线程池用过吗?生产上你是如何设置合理参数 ①. 线程池的拒绝策略请你谈谈 ②. 你在工作中单一的/固定数的/可变你的三种创建线程池的方法,你用哪个多?超级大坑
141 0
Juc05_线程池概述、创建方式、七大参数、底层工作原理、拒绝策略(二)