Spring框架使用xml方式配置ThreadPoolTaskExecutor线程池,并且自定义线程工厂
一、自定义线程工厂
自定义线程工厂需要实现java.util.concurrent.ThreadFactory接口,重写newThread方法。
示例代码:
package com.xiaobai.thread;
import org.apache.log4j.Logger;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 业务自定义线程工程
* @author wangt
*/
public class BusinessThreadFactory implements ThreadFactory {
private final Logger logger = Logger.getLogger(BusinessThreadFactory.class);
// 线程组
private final ThreadGroup group;
// 线程序号
private final AtomicInteger threadNumber = new AtomicInteger(1);
// 线程名称前缀
private final String namePrefix;
public BusinessThreadFactory(String namePrefix) {
SecurityManager securityManager = System.getSecurityManager();
group = securityManager != null ? securityManager.getThreadGroup()
: Thread.currentThread().getThreadGroup();
this.namePrefix = namePrefix + "-thread-";
}
@Override
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(group, runnable, namePrefix + threadNumber.getAndIncrement(), 0);
// 守护线程
if (thread.isDaemon()) {
// 将当前线程设置为守护线程,主线程结束时,当前线程也随之结束
thread.setDaemon(true);
}
// 线程优先级
if (thread.getPriority() != Thread.NORM_PRIORITY) {
// 设置普通优先级
thread.setPriority(Thread.NORM_PRIORITY);
}
// 处理未捕捉的异常
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
logger.error("异常:", e);
}
});
return thread;
}
}
二、applicationContext.xml配置自定义线程工厂及线程池
(一)自定义线程工厂配置
<!--自定义线程工厂-->
<bean id="businessThread" class="com.xiaobai.thread.BusinessThreadFactory" >
<!--自定义线程工厂构造函数,参数为线程名称前缀-->
<constructor-arg value="business" name="namePrefix"/>
</bean>
(二)配置ThreadPoolTaskExecutor线程池
<!--Spring线程池-->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!--核心线程数量-->
<property name="corePoolSize" value="20" />
<!--最大线程数量-->
<property name="maxPoolSize" value="50" />
<!--队列容量-->
<property name="queueCapacity" value="100" />
<!--允许的空闲时间-->
<property name="keepAliveSeconds" value="60" />
<!--线程超过空闲时间限制,会直接退出知道线程数量为0-->
<property name="allowCoreThreadTimeOut" value="true"/>
<!--配置自定义线程工厂-->
<property name="threadFactory" ref="businessThread"/>
</bean>
(三)ThreadPoolTaskExecutor线程池核心参数配置说明:
1、corePoolSize(核心线程数量):
配置核心线程数量需要考虑任务类型和任务负载等因素。
(1)CPU密集型任务:核心线程数量可设置为 CPU 核心数 + 1;
(2)IO密集型任务:核心线程数量可设置为CPU 核心数 × 2,IO操作会导致线程阻塞,更多的线程可提高并发能力;
(3)如果任务负载较轻,可适当减小核心线程数量,如果任务负载较重,可适当增加核心线程数量;
2、maxPoolSize(最大线程数量):
配置最大线程数量需要考虑任务类型和任务负载等因素,最大线程数量应与队列容量匹配。
(1)CPU密集型任务:最大线程数量可设置为 CPU 核心数 + 1到CPU 核心数 ×2之间;
(2)IO密集型任务:最大线程数量可设置为CPU核心数×2到核心数×4之间;
3、queueCapacity(队列容量):
(1)CPU密集型任务:队列容量通常设置为100;
(2)IO密集型任务:队列容量通常设置为200到500;
4、keepAliveTime(空闲线程存活时间):
一个线程如果处于空闲状态,在指定时间内,这个线程会被销毁。
5、allowCoreThreadTimeOut(是否会回收核心线程):
如果核心线程空闲时间超过keepAliveTime,核心线程线程会被回收。
6、rejectedExecutionHandler(拒绝策略):
默认拒绝策略是ThreadPoolExecutor.AbortPolicy,任务数量超过最大线程数量,抛出RejectedExecutionException 异常。
(四)线程池使用
1、注入线程池
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
2、使用线程池创建线程
Runnable runnable = new Runnable() {
@Override
public void run() {
testService.threadTest(user);
}
};
taskExecutor.execute(runnable);
参考
ThreadPoolExecutor拒绝策略
为何自定义线程工厂(ThreadFactory)