ThreadPoolTaskExecutor使用详解

简介: ThreadPoolTaskExecutor使用详解

当我们需要实现并发、异步等操作时,通常都会使用到ThreadPoolTaskExecutor,现对其使用稍作总结。


配置

ThreadPoolTaskExecutor通常通过XML方式配置,或者通过Executors的工厂方法进行配置。

XML方式配置代码如下:


<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="8"/> <!--核心线程数 -->
    <property name="maxPoolSize" value="16"/> <!--最大线程数 -->
    <property name="keepAliveSeconds" value ="3000"/> <!--线程最大空闲时间 -->
    <property name="queueCapacity" value="200"/> <!-- 队列大小 -->
    <property name="threadNamePrefix" value="TASK_EXECUTOR"/>
    <property name="rejectedExecutionHandler">
        <bean class="java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy"/>
    </property>
</bean>

rejectedExecutionHandler字段用于配置拒绝策略,常用的拒绝策略如下:


AbortPolicy,用于被拒绝任务的处理程序,它将抛出RejectedExecutionException。

CallerRunsPolicy,用于被拒绝任务的处理程序,它直接在execute方法的调用线程中运行被拒绝的任务。

DiscardOldestPolicy,用于被拒绝任务的处理程序,它放弃最旧的未处理请求,然后重试execute。

DiscardPolicy,用于被拒绝任务的处理程序,默认情况下它将丢弃被拒绝的任务。


其他说明:


为了实现某些特殊的业务需求,用户可以选择使用自定义策略,只需实现RejectedExecutionHandler接口即可。

建议配置threadNamePrefix属性,出问题时可以更方便的进行排查。

提交任务

无返回值的任务使用execute(Runnable)

有返回值的任务使用submit(Runnable)


处理流程

当一个任务被提交到线程池时,首先查看线程池的核心线程是否都在执行任务,否就选择一条线程执行任务,是就执行第二步。

查看核心线程池是否已满,不满就创建一条线程执行任务,否则执行第三步。

查看任务队列是否已满,不满就将任务存储在任务队列中,否则执行第四步。

查看线程池是否已满,不满就创建一条线程执行任务,否则就按照策略处理无法执行的任务。

在ThreadPoolExecutor中表现为:


如果当前运行的线程数小于corePoolSize,那么就创建线程来执行任务(执行时需要获取全局锁)。

如果运行的线程大于或等于corePoolSize,那么就把task加入BlockQueue。

如果创建的线程数量大于BlockQueue的最大容量,那么创建新线程来执行该任务。

如果创建线程导致当前运行的线程数超过maximumPoolSize,就根据饱和策略来拒绝该任务。

关闭线程池

调用shutdown或者shutdownNow,两者都不会接受新的任务,而且通过调用要停止线程的interrupt方法来中断线程,有可能线程永远不会被中断,不同之处在于shutdownNow会首先将线程池的状态设置为STOP,然后尝试停止所有线程(有可能导致部分任务没有执行完)然后返回未执行任务的列表。而shutdown则只是将线程池的状态设置为shutdown,然后中断所有没有执行任务的线程,并将剩余的任务执行完。


配置线程个数

如果是CPU密集型任务,那么线程池的线程个数应该尽量少一些,一般为CPU的个数+1条线程。

如果是IO密集型任务,那么线程池的线程可以放的很大,如2*CPU的个数。

对于混合型任务,如果可以拆分的话,通过拆分成CPU密集型和IO密集型两种来提高执行效率;如果不能拆分的的话就可以根据实际情况来调整线程池中线程的个数。


监控线程池状态

常用状态:


taskCount:线程需要执行的任务个数。

completedTaskCount:线程池在运行过程中已完成的任务数。

largestPoolSize:线程池曾经创建过的最大线程数量。

getPoolSize获取当前线程池的线程数量。

getActiveCount:获取活动的线程的数量

通过继承线程池,重写beforeExecute,afterExecute和terminated方法来在线程执行任务前,线程执行任务结束,和线程终结前获取线程的运行情况,根据具体情况调整线程池的线程数量。


相关文章
|
3月前
|
设计模式 Java 调度
JUC线程池: ScheduledThreadPoolExecutor详解
`ScheduledThreadPoolExecutor`是Java标准库提供的一个强大的定时任务调度工具,它让并发编程中的任务调度变得简单而可靠。这个类的设计兼顾了灵活性与功能性,使其成为实现复杂定时任务逻辑的理想选择。不过,使用时仍需留意任务的执行时间以及系统的实际响应能力,以避免潜在的调度问题影响应用程序的行为。
76 1
|
3月前
|
Java
多线程 ThreadPoolTaskExecutor 应用
多线程 ThreadPoolTaskExecutor 应用
28 0
|
4月前
|
缓存 Java
Executor
【7月更文挑战第22天】
75 0
|
Java Spring
线程池:第四章:ThreadPoolTaskExecutor和ThreadPoolExecutor有何区别?
线程池:第四章:ThreadPoolTaskExecutor和ThreadPoolExecutor有何区别?
213 0
线程池:第四章:ThreadPoolTaskExecutor和ThreadPoolExecutor有何区别?
|
存储 缓存 安全
Executor - 一文搞懂 ThreadPoolExecutor 与 BlockingQueue
ThreadPool 是 java 的一种多线程处理方式,和前面提到了 RedisPool 类似,即通过一个 pool 批量管理,ThreadPool 管理线程,RedisPool 管理 Jedis 连接。下面主要介绍 ThreadPool 的参数含义,BlockingQueue 的几种类型以及 Executors 下 newCachedThreadPool、newFixedThreadPool、newSingleThreadPool 以及 newScheduleThreadPool 的使用与不同。....
191 0
Executor - 一文搞懂 ThreadPoolExecutor 与 BlockingQueue
|
存储 Java 应用服务中间件
让人思来想去的ThreadPool
一直以来被一个线程池中核心线程跟非核心线程有什么区别的问题困惑着自己,是时候直面恐惧了。
180 0
|
消息中间件 Dubbo Java
“既生 ExecutorService, 何生 CompletionService?”
“既生 ExecutorService, 何生 CompletionService?”
“既生 ExecutorService, 何生 CompletionService?”
|
存储 缓存 监控
ThreadPoolExecutor:线程池不允许使用Executors创建
ThreadPoolExecutor:线程池不允许使用Executors创建
376 0
ThreadPoolExecutor:线程池不允许使用Executors创建
|
人工智能 Java 开发者
threadLocal 和 threadpool | 学习笔记
快速学习 threadLocal 和 threadpool。
146 0
threadLocal 和 threadpool | 学习笔记