资源贴:
ThreadPoolTaskExecutor的配置:https://www.cnblogs.com/lic309/p/4186880.html
ThreadPoolTaskExecutor的架构:https://blog.csdn.net/f641385712/article/details/80832636
拒绝策略:http://blog.sina.com.cn/s/blog_714cb3040102wc6i.html
等待线程执行完毕,在执行主线程:http://www.importnew.com/21889.html
项目地址:https://github.com/wenrongyao/springboot-demo.git
摘要:配置线程池
1、新建线程池配置类,注意这边的启动类是在group id(maven坐标)下,可以直接扫到这个类,如果启动类不在group id下需要在启动类中通过@ImportAutoConfiguration引入。
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Created by rongyaowen
* on 2019/1/4.
*/
@Configuration
@EnableAsync
public class TaskExecutorConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
// 最先线程池,低于这个数,新建线程
threadPoolTaskExecutor.setCorePoolSize(10);
// 最大线程池
threadPoolTaskExecutor.setMaxPoolSize(15);
// 任务队列
threadPoolTaskExecutor.setQueueCapacity(30);
// 任务执行策略
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
2、异步方法执行类
这边为了演示另起了一个包async,实际开发中通常是在service层
@Async写在方法上表示方法异步,写在类上表示所有方法都是异步的。
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* Created by rongyaowen
* on 2019/1/4.
*/
@Component
public class AsyncDemo {
@Async
public void test(int i) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i + "异步线程id:" + Thread.currentThread().getId());
}
}
3、ThreadPoolTaskExecutor的常用配置
corePoolSize:线程池维护线程的最小数量.
maxPoolSize:线程池维护线程的最大数量.
keepAliveSeconds:空闲线程的存活时间.
queueCapacity:持有等待执行的任务队列.
rejectedExecutionHandler:
用来拒绝一个任务的执行,有两种情况会发生这种情况。
一是在execute方法中若addIfUnderMaximumPoolSize(command)为false,即线程池已经饱和;
二是在execute方法中, 发现runState!=RUNNING || poolSize == 0,即已经shutdown,就调用ensureQueuedTaskHandled(Runnable command)
拒绝策略:
Reject策略预定义有四种:
(1)ThreadPoolExecutor.AbortPolicy策略,是默认的策略,处理程序遭到拒绝将抛出运行时 RejectedExecutionException。
(2)ThreadPoolExecutor.CallerRunsPolicy策略 ,只要线程池未关闭,该策略直接在调用者线程中运行当前被丢弃的任务。显然这样不会真的丢弃任务,但是,调用者线程性能可能急剧下降。
(3)ThreadPoolExecutor.DiscardPolicy策略,不能执行的任务将被丢弃(会丢失任务).
(4)ThreadPoolExecutor.DiscardOldestPolicy策略,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程,会丢失任务).
执行顺序:
当一个任务通过 execute(Runnable) 方法欲添加到线程池时,线程池采用的策略如下(即添加任务的策略):
如果此时线程池中的数量小于 corePoolSize ,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
如果此时线程池中的数量等于 corePoolSize ,但是缓冲队列 queueCapacity未满,那么任务被放入缓冲队列。
如果此时线程池中的数量大于 corePoolSize ,缓冲队列 queueCapacity满,并且线程池中的数量小于maxPoolSize ,建新的线程来处理被添加的任务。
如果此时线程池中的数量大于 corePoolSize ,缓冲队列 queueCapacity满,并且线程池中的数量等于maxPoolSize ,那么通过 handler 所指定的策略来处理此任务。
任务处理的优先级(顺序)为:
核心线程 corePoolSize 、任务队列 queueCapacity、最大线程 maxPoolSize ,如果三者都满了,使用 handler处理被拒绝的任务。当线程池中的线程数量大于 corePoolSize 时,如果某线程空闲时间超过 keepAliveTime ,线程将被终止。这样,线程池可以动态的调整池中的线程数。
ThreadPoolTaskExecutor的默认配置
核心线程为1,最大线程和最大队列都是最大整数。所以如果没有配置自己的Executor,即没有TaskExecutorConfig类,只是在启动类上通过@EnableAsync开启异步支持,那么通过@Async配置的方法每次会开启一个新的线程,使用默认配置,这种线程池就是个空壳子,没有什么意义。
4、总结
综上,如果项目中开启线程池任务个数是固定的,那么可以通过配置corePoolSize,maxPoolSize,queueCapacity三个参数来调整,如果参数不定,可以只配置corePoolSize,maxPoolSize参数,queueCapacity使用默认值,即最大,但是这种做法有个问题即使任务堆积。