其实配置线程池没什么好讲的,就那几个参数,不过在项目包中提供了一个帮助类,可以方便的只用传参数,方法内部去构建线程池对象,避免配置多个线程池时每个方法内部产生大量重复代码.
准备
Spring
提供了一些类可以帮助我们快速构建线程池bean对象。
- 基于线程池任务的
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
- 基于定时任务使用的调度线程池对象
org.springframework.scheduling.TaskScheduler
我们现在提供一个类ThreadBuilderHelper
,专门用户构建上述的线程池对象。内部代码很简单,主要就是为了避免重复代码,所以在这个类中统一处理参数赋值,由于重载了几个,所以看起来比较多而已。
package com.ddf.boot.common.core.helper;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 创建线程
* <p>
* _ooOoo_
* o8888888o
* 88" . "88
* (| -_- |)
* O\ = /O
* ___/`---'\____
* . ' \\| |// `.
* / \\||| : |||// \
* / _||||| -:- |||||- \
* | | \\\ - /// | |
* | \_| ''\---/'' | |
* \ .-\__ `-` ___/-. /
* ___`. .' /--.--\ `. . __
* ."" '< `.___\_<|>_/___.' >'"".
* | | : `- \`.;`\ _ /`;.`/ - ` : | |
* \ \ `-. \_ __\ /__ _/ .-` / /
* ======`-.____`-.___\_____/___.-`____.-'======
* `=---='
* .............................................
* 佛曰:bug泛滥,我已瘫痪!
*
* @author dongfang.ding
* @date 2019/12/11 0011 17:52
*/
public class ThreadBuilderHelper {
/**
* 构建线程池参数, 默认拒绝策略是将请求打回给调用线程使用
*
* @param prefix 线程池名称前缀
* @param keepAliveSeconds 保持空闲时间
* @param queueCapacity 队列大小
* @return
*/
public static ThreadPoolTaskExecutor buildThreadExecutor(String prefix, int keepAliveSeconds, int queueCapacity) {
return buildThreadExecutor(prefix, keepAliveSeconds, queueCapacity,
Runtime.getRuntime().availableProcessors() + 1, Runtime.getRuntime().availableProcessors() * 2,
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
/**
* 构建线程池参数, 默认拒绝策略是将请求打回给调用线程使用
*
* @param prefix 线程池名称前缀
* @param keepAliveSeconds 保持空闲时间
* @param queueCapacity 队列大小
* @param corePoolSize 核心线程池大小
* @param maxPoolSize 最大线程池大小
* @return org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
* @author dongfang.ding
* @date 2019/12/11 0011 17:59
**/
public static ThreadPoolTaskExecutor buildThreadExecutor(String prefix, int keepAliveSeconds, int queueCapacity,
int corePoolSize, int maxPoolSize) {
return buildThreadExecutor(prefix, keepAliveSeconds, queueCapacity, corePoolSize, maxPoolSize,
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
/**
* 构建线程池参数
*
* @param prefix 线程池名称前缀
* @param keepAliveSeconds 保持空闲时间
* @param queueCapacity 队列大小
* @return
*/
public static ThreadPoolTaskExecutor buildThreadExecutor(String prefix, int keepAliveSeconds, int queueCapacity,
RejectedExecutionHandler rejectedExecutionHandler) {
return buildThreadExecutor(prefix, keepAliveSeconds, queueCapacity,
Runtime.getRuntime().availableProcessors() + 1, Runtime.getRuntime().availableProcessors() * 2,
rejectedExecutionHandler
);
}
/**
* 构建线程池参数
*
* @param prefix 线程池名称前缀
* @param keepAliveSeconds 保持空闲时间
* @param queueCapacity 队列大小
* @param corePoolSize 核心线程池大小
* @param maxPoolSize 最大线程池大小
* @param rejectedExecutionHandler 队列满之后的处理策略
* @return org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
* @author dongfang.ding
* @date 2019/12/11 0011 17:59
**/
public static ThreadPoolTaskExecutor buildThreadExecutor(String prefix, int keepAliveSeconds, int queueCapacity,
int corePoolSize, int maxPoolSize, RejectedExecutionHandler rejectedExecutionHandler) {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix(prefix);
threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
threadPoolTaskExecutor.setRejectedExecutionHandler(rejectedExecutionHandler);
return threadPoolTaskExecutor;
}
/**
* 构建定时任务线程池
*
* @param prefix
* @param keepAliveSeconds
* @return
*/
public static ScheduledThreadPoolExecutor buildScheduledExecutorService(String prefix, int keepAliveSeconds) {
return buildScheduledExecutorService(prefix, Runtime.getRuntime().availableProcessors() + 1,
Runtime.getRuntime().availableProcessors() * 2, keepAliveSeconds
);
}
/**
* 构建定时任务线程池
*
* @param prefix
* @param corePoolSize
* @param maxPoolSize
* @return
*/
public static ScheduledThreadPoolExecutor buildScheduledExecutorService(String prefix, int corePoolSize,
int maxPoolSize, int keepAliveSeconds) {
ThreadFactory namedThreadFactory = new CustomizableThreadFactory(prefix);
ScheduledThreadPoolExecutor scheduledExecutorService = new ScheduledThreadPoolExecutor(corePoolSize,
namedThreadFactory
);
scheduledExecutorService.setMaximumPoolSize(maxPoolSize);
scheduledExecutorService.setKeepAliveTime(keepAliveSeconds, TimeUnit.SECONDS);
return scheduledExecutorService;
}
}
定义和使用
将线程池对象注入到配置类中,这个由于是在通用包中,因此线程池对象加了注解@Primary
, 当使用方也自定义线程池,但是没有指定具体用哪个的时候,可以用这个默认的来兜底。这个就是一个全局的默认线程池。当然如果还需要在项目其它地方定义的话,按照下面这种方式,但是不要加@Primary
即可。
注意,单独这个功能@EnableAsync
是不需要的。
@Configuration
@EnableAsync
@EnableScheduling
public class CoreWebConfig {
/**
* 默认线程池
*
* @return
*/
@Bean
@Primary
public ThreadPoolTaskExecutor defaultThreadPool() {
return ThreadBuilderHelper.buildThreadExecutor("default-thread-pool", 60, 1000);
}
/**
* 定时任务调度线程池
*
* @return
*/
@Bean
@Primary
public TaskScheduler scheduledExecutorService() {
ThreadPoolTaskScheduler threadPoolScheduler = new ThreadPoolTaskScheduler();
threadPoolScheduler.setThreadNamePrefix("scheduledExecutorService-");
threadPoolScheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
threadPoolScheduler.setRemoveOnCancelPolicy(true);
return threadPoolScheduler;
}
}
在其它容器类中,需要想要使用线程池,则直接注入即可.
@Service
public class BizService {
@Autowired
private ThreadPoolTaskExecutor defaultThreadPool;
public void doBiz() {
defaultThreadPool.execute(() -> {
// do something
});
}
}
当然还有一些方法,天生就是异步的,不想使用上面的那种方式,那么由于上面的配置类开启了注解@EnableAsync
,那么可以在方法上标识一个方法为异步方法,并指定线程池bean的名称。
然后其他业务类直接调用这个方法即可,但是要注意,采用这种方式的时候调用代码不能和被调用方在一个类中,否则代理会失效。
@Component
public class AsyncTask {
@Async(value = "defaultThreadPool")
public void doBiz {
// do something
}
}