当前位置:   article > 正文

ThreadPoolTaskExecutor和ThreadPoolExecutor区别_threadpoolexecutor 区别

threadpoolexecutor 区别

工作中发现, 在创建线程池的时候,有些同事使用ThreadPoolTaskExecutor,有些同事则使用ThreadPoolExecutor,容易令人混淆。于是,决定探究下这两个线程池的区别以及使用,也方便其他同学理解清楚。

一、ThreadPoolExecutor

ThreadPoolExecutor是JDK中的线程池类,实现了Executor接口。 顾名思义,Executor 是一个专门用来处理多线程工作的接口,所有多线程处理相关的类都实现了这个接口。线程池主要提供一个线程队列,队列中保存着所有等待状态的线程,降低了线程频繁创建与销毁的开销,提高了响应的速度。ThreadPoolExecutor相关的继承实现类图如下所示:

1.1 线程池接口

ExecutorService为线程池接口,提供了线程池生命周期管理方法,继承自Executor接口。ThreadPoolExecutor为线程池实现类,提供了线程池的维护操作等相关方法,继承自AbstractExecutorService抽象类,AbstractExecutorService实现了ExecutorService接口。

1.2 线程池的体系结构

java.util.concurrent.Executor 线程使用和调度的根接口。
        |--ExecutorService 子接口: 线程池的主要接口。
                |--ThreadPoolExecutor 线程池的实现类
                |--ScheduledExceutorService 子接口: 负责线程的调度。
                    |--ScheduledThreadPoolExecutor : 继承了ThreadPoolExecutor,实现了ScheduledExecutorService。

1.3 Executors工具类 

Executors为线程池工具类,相当于一个工厂类,用来创建合适的线程池,返回ExecutorService接口类型的线程池。其包含如下方法:
ExecutorService newFixedThreadPool() : 创建固定大小的线程池。
ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
ExecutorService newSingleThreadExecutor() : 创建只有一个线程的线程池。 

ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时执行任务。

其中,AbstractExecutorService是它们的抽象父类,继承自ExecutorService。ExecutorService 接口继承自Executor接口,增加了生命周期方法。

实际应用中,我一般比较喜欢使用Exectuors工厂类来创建线程池,其有五个方法,分别创建不同的线程池。例如,使用newFixedThreadPool创建一个制定大小的线程池,Exectuors工厂实际上就是调用传入默认参数的ThreadPoolExecutor构造方法。当然,我们也可以直接执行new ThreadPoolExecutor构造方法来创建线程池,传入需要的参数即可。

二、ThreadPoolTaskExecutor

ThreadPoolTaskExecutor这个类则是spring包下的,是sring为我们提供的线程池类。这里重点讲解这个类的用法。

2.1 创建ThreadPoolTaskExecutor线程池

可以使用基于xml配置的方式创建ThreadPoolTaskExecutor类型的线程池。

  1. <!-- spring线程池 -->
  2. <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
  3. <!-- 核心线程数 -->
  4. <property name="corePoolSize" value="10"/>
  5. <!-- 最大线程数 -->
  6. <property name="maxPoolSize" value="200"/>
  7. <!-- 队列最大长度 >=mainExecutor.maxSize -->
  8. <property name="queueCapacity" value="10"/>
  9. <!-- 线程池维护线程所允许的空闲时间 -->
  10. <property name="keepAliveSeconds" value="20"/>
  11. <!-- 线程池对拒绝任务(无线程可用)的处理策略 -->
  12. <property name="rejectedExecutionHandler">
  13. <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
  14. </property>
  15. </bean>

或者,通过配置类的方式配置线程池。

  1. @Configuration
  2. public class ExecturConfig {
  3. @Bean("taskExector")
  4. public Executor taskExector() {
  5. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  6. int i = Runtime.getRuntime().availableProcessors();//获取到服务器的cpu内核
  7. executor.setCorePoolSize(5);//核心池大小
  8. executor.setMaxPoolSize(100);//最大线程数
  9. executor.setQueueCapacity(1000);//队列程度
  10. executor.setKeepAliveSeconds(1000);//线程空闲时间
  11. executor.setThreadNamePrefix("tsak-asyn");//线程前缀名称
  12. executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//配置拒绝策略
  13. return executor;
  14. }

然后,通过自动注入的方式注入线程池。

  1. @Resource(name="taskExecutor")
  2. ThreadPoolTaskExecutor taskExecutor;
  3. // 或者可以直接@Autowried
  4. @AutoWired
  5. ThreadPoolTaskExecutor taskExecutor

上面注释中已经解释了各参数的含义,这里重点讲解一下spring线程池的拒绝策略和处理流程。

2.2 spring线程池的拒绝策略

rejectedExectutionHandler参数用于配置绝策略,常用拒绝策略如下:

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

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

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

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

线程池处理流程:

1.查看核心线程池是否已满,若不满,则创建一个线程执行任务;否则,执行第二步。

2.查看任务队列是否已满,若不满,则将任务存储在任务队列中;否则,执行第三步。

3.查看线程池是否已满,即是否达到最大线程池数,若不满,则创建一个线程执行任务;否则,就按照策略处理新到的任务。

如果任务队列已满,并且已达到最大处理线程数,这时候不想丢失当前新到任务,则可以使用自定义阻塞拒绝策略,如下所示:

  1. import java.util.concurrent.RejectedExecutionHandler;
  2. import java.util.concurrent.ThreadPoolExecutor;
  3. public class TaskRejectedHandler implements RejectedExecutionHandler{
  4. @Override
  5. public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
  6. try {
  7. executor.getQueue().put(r);
  8. } catch (Exception e) {
  9. }
  10. }
  11. }

如此,即可阻塞线程池execute方法继续提交任务到工作队列,使得当前新到任务不丢失,阻塞等待空闲线程处理。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/104699
推荐阅读
  

闽ICP备14008679号