一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
一、简介
ThreadPoolTaskExecutor是spring框架基于JDK中ThreadPoolExecutor的,在它的基础上进行了一层封装。Spring通过配置的方式把ThreadPoolExecutor的核心属性暴露出来,让用户可以自定义配置并注入到当前容器,由容器进行管理。
二、使用
目前应用大多是基于springBoot开发,在springBoot中有默认的对线程池的配置
主要通过TaskExecutionAutoConfiguration这个类进行配置,核心属性在TaskExecutionProperties中,可通过JAVAConfig的方式,修改线程池的配置。通过配置可以把ThreadPoolTaskExecutor注入到容器,并且覆盖springBoot原本的配置信息
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
// 核心线程数
poolExecutor.setCorePoolSize(5);
// 最大线程数
poolExecutor.setMaxPoolSize(15);
// 队列大小
poolExecutor.setQueueCapacity(100);
// 线程最大空闲时间
poolExecutor.setKeepAliveSeconds(300);
// 拒绝策略
poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 线程名称前缀
poolExecutor.setThreadNamePrefix("my-task-pool-");
return poolExecutor;
}
通过配置文件方式修改配置信息
# 核心线程数
spring.task.execution.pool.core-size=8
# 最大线程数
spring.task.execution.pool.max-size=16
# 空闲线程存活时间
spring.task.execution.pool.keep-alive=60s
# 是否允许核心线程超时
spring.task.execution.pool.allow-core-thread-timeout=true
# 线程队列数量
spring.task.execution.pool.queue-capacity=100
# 线程关闭等待
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
# 线程名称前缀
spring.task.execution.thread-name-prefix=task-
ThreadPoolExecutor主要有以下几个方法
public void execute(Runnable task)
public void execute(Runnable task, long startTimeout)
public Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
public ListenableFuture<?> submitListenable(Runnable task)
public <T> ListenableFuture<T> submitListenable(Callable<T> task)
- 相比 ThreadPoolExecutor,ThreadPoolTaskExecutor 增加了 submitListenable 方法,该方法返回 ListenableFuture 接口对象
- ListenableFuture 接口对象,增加了线程执行完毕后成功和失败的回调方法。从而避免了 Future 需要以阻塞的方式调用 get,然后再执行成功和失败的方法。
- ListenableFuture 相比 Future 是不需要知道 执行结果的情况下就可以将 成功或者失败的业务代码 通过回调的方式 预埋,带来的好处就是异步,不需要阻塞当前线程,从而可以提高系统的吞吐量。
- Future 需要通过 get() 方法阻塞当前线程,在获取线程的执行结果后再根据执行结果编写相关的业务代码
三、例子
public static void main(String[] args) {
ThreadPoolTaskExecutor executorService = new ThreadPoolTaskExecutor();
executorService.setCorePoolSize(1);
executorService.setMaxPoolSize(1);
executorService.initialize();
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
ListenableFuture<Boolean> asyncResult = executorService.submitListenable(() -> {
// 休息5毫秒,模拟执行
TimeUnit.MILLISECONDS.sleep(5);
//throw new RuntimeException("出现异常");
return true;
});
asyncResult.addCallback(data -> {
try {
// 休息3毫秒模拟获取到执行结果后的操作
TimeUnit.MILLISECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
}
}, ex -> logger.info("**异常信息**:{}", ExceptionUtils.getExceptionMsg(ex)));
}
System.out.println(String.format("总结耗时:%s", System.currentTimeMillis() - start));
}
四、总结
spring中@Async也是基于线程池,如果有自定义的线程池就此注解的方法就使用自定义的线程池。使用@Async需要在启动上增加注解,并且在需要异步执行的方法上增加@Async注解。
@SpringBootApplication
@EnableAsync
public class ThreadpoolApplication {
public static void main(String[] args) {
SpringApplication.run(ThreadpoolApplication.class, args);
}
}