Spring/SpringBoot自定义线程池
在 Spring/SpringBoot 中,可以使用 @Configuration 和 @Bean 去设置线程池,用 @Value 去做线程池的参数配置。
依赖包:
引用 google 的 guava包。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
线程池配置:
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.*;
@Configuration
public class ThreadPoolExecutorConfig {
/**
* 核心线程数, :冒号后面是默认值
*/
@Value("${executor.core.pool.size:20}")
private int corePoolSize;
/**
* 最大线程数, :冒号后面是默认值
*/
@Value("${executor.max.pool.size:100}")
private int maxPoolSize;
/**
* 没有任务执行时,线程的存活时间
*/
@Value("${executor.keep.alive.time:2}")
private int keepAliveTime;
/**
* 阻塞队列长度
*/
@Value("${executor.blocking.queue.size:200}")
private int blockingQueueSize;
/**
* 使用 @Bean 指定线程池的名称
*
*/
@Bean("myExecutor")
public Executor myExecutor() {
//阻塞队列长度
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(blockingQueueSize);
//创建线程或线程池时指定有意义的线程名称,方便出错时回溯。名称如果过长,会被截断。
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("my-executor-%d").build();
//可以自定义拒绝策略,也可以不加这个参数,构造方法会直接用默认的拒绝策略
ThreadPoolExecutor.AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();
return new ThreadPoolExecutor(corePoolSize, maxPoolSize,
keepAliveTime, TimeUnit.SECONDS, workQueue, threadFactory, abortPolicy);
}
/**
* 不同的业务,有时可以使用不同的线程池、不同的配置。
* 如果核心业务跟普通业务,用同一个线程池,普通业务可能会占用过多的线程数,导致核心业务受影响。
*/
@Bean("myExecutor2")
public Executor myExecutor2() {
//阻塞队列长度
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(blockingQueueSize);
//创建线程或线程池时指定有意义的线程名称,方便出错时回溯。
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("my-executor2-%d").build();
//可以自定义拒绝策略,也可以不加这个参数,构造方法会直接用默认的拒绝策略
ThreadPoolExecutor.AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();
return new ThreadPoolExecutor(corePoolSize, maxPoolSize,
keepAliveTime, TimeUnit.SECONDS, workQueue, threadFactory, abortPolicy);
}
}
配置参数:
可以写到配置中心里面,如果没有配置中心,放到 propeties 文件也行。
executor.core.pool.size=20
executor.max.pool.size=100
executor.keep.alive.time=2
executor.blocking.queue.size=200
使用线程池:
日志框架自行补充,可以在Service类上面用 lombok的 @Slf4j 注解,也可以用其他的日志。
@Service
@Slf4j
public class MyService {
@Resource(name = "myExecutor")
private Executor executor;
public void execute() {
executor.execute(() -> log.info("线程池执行任务."));
}
}
运行,查看日志:
INFO 18876 --- [ my-executor-0] com.example.demo.threadpool.MyService : 线程池执行任务.
可以看到 线程池已经执行任务。日志中的 线程名称 是 my-executor 开头的。
把MyService 类中的 (name = "myExecutor") 换成 (name = "myExecutor2") ,再次运行,查看日志:
INFO 18876 --- [ my-executor2-0] com.example.demo.threadpool.MyService : 线程池执行任务.
可以看到日志,线程池已经执行任务。 线程名称 变成 了 my-executor2 开头的了。
创建线程或线程池时,指定有意义的线程名称,方便出错时回溯。