首页 > 其他分享 >ThreadPoolTaskExecutor和ThreadPoolExecutor区别

ThreadPoolTaskExecutor和ThreadPoolExecutor区别

时间:2022-08-30 13:45:40浏览次数:50  
标签:区别 接口 任务 线程 executor ExecutorService 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类型的线程池。

<!-- spring线程池 -->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数 -->
<property name="corePoolSize" value="10"/>
<!-- 最大线程数 -->
<property name="maxPoolSize" value="200"/>
<!-- 队列最大长度 >=mainExecutor.maxSize -->
<property name="queueCapacity" value="10"/>
<!-- 线程池维护线程所允许的空闲时间 -->
<property name="keepAliveSeconds" value="20"/>
<!-- 线程池对拒绝任务(无线程可用)的处理策略 -->
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
</property>
</bean>
或者,通过配置类的方式配置线程池。

@Configuration
public class ExecturConfig {
@Bean("taskExector")
public Executor taskExector() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int i = Runtime.getRuntime().availableProcessors();//获取到服务器的cpu内核
executor.setCorePoolSize(5);//核心池大小
executor.setMaxPoolSize(100);//最大线程数
executor.setQueueCapacity(1000);//队列程度
executor.setKeepAliveSeconds(1000);//线程空闲时间
executor.setThreadNamePrefix("tsak-asyn");//线程前缀名称
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//配置拒绝策略
return executor;
}
然后,通过自动注入的方式注入线程池。

@Resource(name="taskExecutor")
ThreadPoolTaskExecutor taskExecutor;
// 或者可以直接@Autowried
@AutoWired
ThreadPoolTaskExecutor taskExecutor
上面注释中已经解释了各参数的含义,这里重点讲解一下spring线程池的拒绝策略和处理流程。

2.2 spring线程池的拒绝策略
rejectedExectutionHandler参数用于配置绝策略,常用拒绝策略如下:

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

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

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

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

线程池处理流程:

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

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

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

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

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

public class TaskRejectedHandler implements RejectedExecutionHandler{
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
executor.getQueue().put(r);
} catch (Exception e) {
}
}
}
如此,即可阻塞线程池execute方法继续提交任务到工作队列,使得当前新到任务不丢失,阻塞等待空闲线程处理。

标签:区别,接口,任务,线程,executor,ExecutorService,ThreadPoolTaskExecutor,ThreadPoolExecutor
From: https://www.cnblogs.com/liftsail/p/16638984.html

相关文章

  • Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用
    一、ThreadPoolTaskExecutor本文采用Executors的工厂方法进行配置。1、将线程池用到的参数定义到配置文件中在项目的resources目录下创建executor.properties文件......
  • wait与sleep区别
    wait与sleep区别在于:wait会释放所有锁而sleep不会释放锁资源.wait只能在同步方法和同步块中使用,而sleep任何地方都可以.wait无需捕捉异常,而sleep需要.两者相同点:都会......
  • delete和truncate删除表数据的区别
    相同点:1,都能删除表数据,都不会删除表结构不同点:1,delete删除表数据时自增不归零,truncate清空表自增归零,重新设置自增列2,truncate清空表数据不会影响事务 拓展:delete删......
  • vue2和vue3的区别?
    vue2和vue3的主要区别在于以下几点:1、生命周期函数钩子不同2、数据双向绑定原理不同3、定义变量和方法不同4、指令和插槽的使用不同5、API类型不同6、是否支持碎片7......
  • BrowserRouter和HashRouter的区别
    底层原理不一样BrowserRouter使用的是H5的historyAPI,不兼容IE9及以下版本。HashRouter使用的是URL的hash值path表现形式不一样BrowserRouter的路径中没有#Has......
  • Oracle 服务名/实例名,Service_name 和Sid的区别
    Oracle服务名/实例名,Service_name和Sid的区别 Service_name和Sid的区别Service_name:该参数是由oracle8i引进的。在8i以前,使用SID来表示标识数据库的一个实例,但是在......
  • Mysql Count的区别
    1.count(1)和count(*)执行计划从执行计划来看count(1)和count()的效果是一样的。当表的数据量大些时(1W以上),对表作分析之后,使用count(1)比使用count()用时多。当......
  • Linux输出重定向>和>>的区别是什么?
    Linux输出重定向>和>>的区别是什么-百度经验 https://jingyan.baidu.com/article/358570f64345c4ce4724fcba.htmlLinux输出重定向有>和>>,如果不清楚他们的区别,混淆......
  • unix kill -9 与kill 有什么区别
    unixkill-9与kill有什么区别_百度知道 https://zhidao.baidu.com/question/289182098.html区别:1、kill-9id:一般不加参数kill是使用15来杀,这相当于正常停止进程,停......
  • stopPropagation, preventDefault 和 return false 的区别
    stopPropagation阻止事件的冒泡和捕获。因为事件可以在各层级的节点中传递,不管是冒泡还是捕获,有时我们希望事件在特定节点执行完之后不再传递,可以使用事件对象的s......