版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_31463999/article/details/82588396
之前已经介绍过如何编写自定义starter,如不明白请参考springboot自定义Starter
今天来介绍一下如何编写一个我们自定义的多线程快速启动starter
功能点:
- 通过配置可实现多个线程池的初始化
- 通过直接决定此方法使用哪个线程池
创建maven工程
略
编写pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>iotstarter</artifactId>
<groupId>com.iot</groupId>
<version>0.0.1-RELEASES</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<groupId>com.iot</groupId>
<artifactId>iot-async-spring-boot-starter</artifactId>
<version>0.0.1-RELEASES</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
</project>
编写配置文件类实体
/**
* 描述:异步线程池配置类
* @author: myx
* @date: 2018/6/17
* Copyright © 2018-hotpot. All rights reserved.
*/
@Data
public class AsyncEntity {
/**
* 核心线程数:线程池创建时候初始化的线程数
*/
private int corePoolSize=10;
/**
* 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
*/
private int maxPoolSize=20;
/**
* 缓冲队列:用来缓冲执行任务的队列
*/
private int queueCapacity=2000;
/**
* 允许线程的空闲时间(秒):当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
*/
private int keepAliveSeconds=60;
/**
*设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
*/
private int awaitTerminationSeconds=10;
/**
* 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
*/
private String threadName;
}
编写配置实体(读取配置文件信息)
/**
* 描述:异步线程管理
* @author: myx
* @date: 2018/6/17
* Copyright © 2018-hotpot. All rights reserved.
*/
@ConfigurationProperties(prefix = "iot-async")
@Data
public class AsyncProperties {
List<AsyncEntity> list =new ArrayList<>();
}
说明:list存放所有线程池配置信息
编写总配置类(初始化单例bean)
/**
* 描述:异步调用线程池管理类
* @author: myx
* @date: 2018/6/17
* Copyright © 2018-hotpot. All rights reserved.
*/
@EnableAsync
@Configuration
@ConditionalOnProperty//存在对应配置信息时初始化该配置类
(
prefix = "iot-async",//存在配置前缀
name = "isopen",
havingValue = "true",//开启
matchIfMissing = true//缺失检查
)
@EnableConfigurationProperties(AsyncProperties.class)//开启使用映射实体对象
public class AsyncConfig {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private AsyncProperties asyncProperties;
@Autowired
private ApplicationContext applicationContext;
/**
* 动态生成多个线程池
* 这个方法返回Runnable只是一个幌子,最重要的是执行方法里面的代码
* @return
* @throws Exception
*/
@Bean
public Runnable dynamicConfiguration() throws Exception
{
ConfigurableApplicationContext context = (ConfigurableApplicationContext)applicationContext;
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)context.getBeanFactory();
List<AsyncEntity> asyncEntityList = asyncProperties.getList();
for (AsyncEntity asyncEntity : asyncEntityList) {
//开始注册异步线程池
log.info("Start the registration of asynchronous thread pool===>"+ JSONUtil.toJsonStr(asyncEntity));
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(ThreadPoolTaskExecutor.class);
beanDefinitionBuilder.addPropertyValue("corePoolSize", asyncEntity.getCorePoolSize());
beanDefinitionBuilder.addPropertyValue("maxPoolSize", asyncEntity.getMaxPoolSize());
beanDefinitionBuilder.addPropertyValue("queueCapacity", asyncEntity.getQueueCapacity());
beanDefinitionBuilder.addPropertyValue("keepAliveSeconds", asyncEntity.getKeepAliveSeconds());
beanDefinitionBuilder.addPropertyValue("threadNamePrefix", asyncEntity.getThreadName()+"-");
//该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
beanDefinitionBuilder.addPropertyValue("waitForTasksToCompleteOnShutdown", true);
beanDefinitionBuilder.addPropertyValue("awaitTerminationSeconds", 10);
/**
* 程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
*/
beanDefinitionBuilder.addPropertyValue("rejectedExecutionHandler",new ThreadPoolExecutor.CallerRunsPolicy());
/**
* 注册到spring容器中
*/
beanFactory.registerBeanDefinition(asyncEntity.getThreadName(), beanDefinitionBuilder.getBeanDefinition());
log.info("End the registration of asynchronous thread pool===>"+asyncEntity.getThreadName());
}
return null;
}
/**
* 核心线程数10:线程池创建时候初始化的线程数
*最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
*缓冲队列200:用来缓冲执行任务的队列
*允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
*线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
*线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
* @return
*/
// @Bean(AsyncEnum.DEFAULT_EXECUTOR)
// public Executor defaultExecutor() {
// ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// executor.setCorePoolSize(10);
// executor.setMaxPoolSize(20);
// executor.setQueueCapacity(20000);
// executor.setKeepAliveSeconds(60);
// executor.setThreadNamePrefix(AsyncEnum.DEFAULT_EXECUTOR+"-");
//该方法就是这里的关键,用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,这样这些异步任务的销毁就会先于Redis线程池的销毁
// executor.setWaitForTasksToCompleteOnShutdown(true);
//该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
// executor.setAwaitTerminationSeconds(60);
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// return executor;
// }
}
在resource/WEB-INF创建spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.iot.async.config.AsyncConfig
完成
使用说明
maven依赖引入
<dependency>
<groupId>com.iot</groupId>
<artifactId>iot-async-spring-boot-starter</artifactId>
<version>最新稳定版</version>
</dependency>
配置文件配置信息
iot-async:
isopen: true #开启线程池配置
list:
- threadName: taskExecutor #线程池名称
corePoolSize: 10 #核心线程数
maxPoolSize: 20 #最大线程数
queueCapacity: 2000 #缓冲队列
keepAliveSeconds: 60 #允许线程的空闲时间(秒)
- threadName: taskExecutor1 #线程池名称
corePoolSize: 10 #核心线程数
maxPoolSize: 20 #最大线程数
queueCapacity: 2000 #缓冲队列
keepAliveSeconds: 60 #允许线程的空闲时间(秒)
如何使用:
定义一个异步任务类
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class Task {
@Async("taskExecutor")
public void doTaskOne() throws Exception {
log.info("开始做任务一");
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
System.out.print("0");
}
long end = System.currentTimeMillis();
log.info("完成任务一,耗时:" + (end - start) + "毫秒");
}
@Async("taskExecutor1")
public void doTaskTwo() throws Exception {
log.info("开始做任务二");
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
System.out.print("1");
}
long end = System.currentTimeMillis();
log.info("完成任务二,耗时:" + (end - start) + "毫秒");
}
@Async("taskExecutor")
public void doTaskThree() throws Exception {
log.info("开始做任务三");
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
System.out.print("2");
}
long end = System.currentTimeMillis();
log.info("完成任务三,耗时:" + (end - start) + "毫秒");
}
}
使用异步类
import com.ganinfo.task.Task;
import lombok.SneakyThrows;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
private Task task;
@Test
@SneakyThrows
public void test() {
for (int i = 0; i < 100; i++) {
task.doTaskOne();
task.doTaskTwo();
task.doTaskThree();
}
}
}