Spring 线程池简单使用
之前简单介绍过Java自带的四种线程池的工厂方法。飞机
《阿里巴巴 Java开发手册》1.6并发处理
第二条
【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。
第三条
【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。
说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决
资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或
者“过度切换”的问题。
第四条
【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样
的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1). FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2). CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
线程池配置
根据不同的业务配置不同的线程池, 对不通业务线程池命名,方便出错时回溯。
/**
* @author yiidii Wang
* @desc 线程池配置
*/
@Configuration
@EnableAsync
public class ExecutorConfig {
/**
* 采集和分析线程的定时线程池(一般就两个线程)
* @return
*/
@Bean("collectionScheduleExcutor")
public Executor collectionScheduleExcutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("collectionScheduleExcutor-");
executor.setMaxPoolSize(5);
executor.setCorePoolSize(2);
executor.setQueueCapacity(0);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
/**
* CollectProxy线程的线程池
* @return
*/
@Bean("timerCollectExecutor")
public Executor timerCollectExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("timerCollectExecutor");
executor.setMaxPoolSize(20);
executor.setCorePoolSize(15);
executor.setQueueCapacity(1000);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
线程池的拒绝策略
线程池拒绝策略参考文章 Java线程池的拒绝策略
通过实现 RejectedExecutionHandler 接口扩展
/**
* @author yiidii Wang
* @desc 采集器线程池拒绝策略
*/
private static final class MyTimerCollectionRejectedExecutionHandler implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 启用新的线程
try {
final Thread t = new Thread(r, "Temporary task executor");
t.start();
} catch (Throwable e) {
throw new RejectedExecutionException(
"Failed to start a new thread", e);
}
}
}
使用
启动新增注解
@SpringBootApplication
@EnableScheduling
public class PigeonApplication {
public static void main(String[] args) {
SpringApplication.run(PigeonApplication.class, args);
}
}
方法异步执行
/**
* 每一秒执行一次
*/
@Async("collectionScheduleExcutor")
@Scheduled(cron = "0/1 * * * * ?")
public void startTimerCollect() {}
如果需要注入线程池
/**
* 采集的线程池
*/
@Autowired
@Resource(name = "timerCollectExecutor")
private ThreadPoolTaskExecutor timerCollectExecutor;