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),你可以将未使用的线程死亡。

目录
相关文章
|
2月前
|
安全 Java
【亮剑】Java中的`Future`接口代表异步计算结果,常与`ExecutorService`配合启动任务并获取结果
【4月更文挑战第30天】Java中的`Future`接口代表异步计算结果,常与`ExecutorService`配合启动任务并获取结果。`Future`接口提供`isDone()`、`get()`、`get(timeout, unit)`和`cancel(mayInterruptIfRunning)`等方法。`FutureTask`是`Future`的实现类,可作为`Runnable`执行并返回结果。
|
2月前
|
安全 Java 调度
【C/C++ 线程池设计思路 】设计与实现支持优先级任务的C++线程池 简要介绍
【C/C++ 线程池设计思路 】设计与实现支持优先级任务的C++线程池 简要介绍
77 2
|
11月前
|
缓存 Java 数据库连接
线程的创建、Lambda函数式接口?Runnable和Callable之间的适配?动态修改线程任务?这里带你图解Java线程池
上面只是提到了对于Thread执行任务的一种动态实现方法,肯定还有其他的。 那么动态实现有什么好处呢? 当我们有很多个任务的时候,我们如果一直使用new,再让gc的话,那么对于系统资源的消耗无疑是巨大的。 那么这个时候,如果我们固定一下,专门拿几个线程来处理并发任务呢?但是当并发任务很多又该怎么办? 这个时候就引入了池化思想 —— Pool 什么是池? 在学JDBC的时候我们知道了连接池,在学Spring的时候,我们又接触到了对象池。 其实按理来说线程池应该是大家在初学JavaSE的时候应该就遇到的,这里我们再来讲一下。 线程池,就是用一个容器来管理线程,这个容器叫做池(Poo
96 0
线程的创建、Lambda函数式接口?Runnable和Callable之间的适配?动态修改线程任务?这里带你图解Java线程池
|
12月前
|
存储 安全 Java
Java 中的线程池:线程池的作用、组成部分、使用方法、最佳实践
Java 中的线程池:线程池的作用、组成部分、使用方法、最佳实践
380 0
Java面试必问之线程池的创建使用、线程池的核心参数、线程池的底层工作原理
Java面试必问之线程池的创建使用、线程池的核心参数、线程池的底层工作原理
145 0
Java面试必问之线程池的创建使用、线程池的核心参数、线程池的底层工作原理
|
存储 Java 调度
【多线程:线程池】ThreadPoolExecutor类的基本概念
【多线程:线程池】ThreadPoolExecutor类的基本概念
126 0
|
算法 Java 应用服务中间件
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(上)
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(上)
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(上)
|
存储 Java 程序员
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(下)
【小家java】用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)(下)
|
安全 IDE Java
高并发之——通过ThreadPoolExecutor类的源码深度解析线程池执行任务的核心流程
打开你的IDE,踏下心来,跟着文章看代码,相信你定能收货满满!!!
151 0
高并发之——通过ThreadPoolExecutor类的源码深度解析线程池执行任务的核心流程