使用SpringBoot内置多线程
SpringBoot使用多线程
一 概述
1 为什么使用多线程
在我们开发系统过程中,经常会处理一些好费时间的任务(如向数据库中插入上百万数据,将会导致系统阻塞),这个时候就会自然想到使用多线程。
当数据量大的时候,一个新的线程满足不了系统的要求,但是只有少量的请求可以直接new一个新线程,如下代码。
// 少量请求可以这样做 new Thread(){ @Override public void run() { //TODO异步任务 } }.start();
2 为什么使用Spring来实现多线程
使用Spring比使用JDK原生的并发API更简单。(@Async就能解决)。
一般的开发环境都会集成Spring框架,Bean也都交给Spring来管理,因此,Spring实现多线程更简单。
3 为什么需要使用异步(多线程)
传统的调用方式:调用一个服务,需要等待服务调用完成后,才能执行后面的代码,因此,需要等待时间。
使用异步的方式:调用一个服务的同时,继续执行后面的代码,几乎是不需要多少的等待时间。
二 SpringBoot使用多线程
1 如何使用
在 SpringBoot 中对其进行了简化处理,只需要配置一个类型为 java.util.concurrent.TaskExecutor
或其子类( 一般使用 Spring 提供的ThreadPoolTaskExecutor 类)的Bean,并在配置类或直接在程序入口类上声明注解 @EnableAsync。
调用也简单,在由Spring管理的对象的方法上标注注解 @Async,显式调用即可生效。
2 配置多线程
通过新增配置类的方式,使用 ThreadPoolTaskExecutor配置Bean
@Configuration // 通过注解启用异步任务 @EnableAsync public class ThreadConfig { @Bean public ThreadPoolTaskExecutor executor(){ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //配置核心线程数 executor.setCorePoolSize(15); //配置最大线程数 executor.setMaxPoolSize(30); //配置队列大小 executor.setQueueCapacity(1000); //线程的名称前缀 executor.setThreadNamePrefix("Executor-"); //线程活跃时间(秒) //executor.setKeepAliveSeconds(60); //等待所有任务结束后再关闭线程池 executor.setWaitForTasksToCompleteOnShutdown(true); //设置拒绝策略 //executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //执行初始化 executor.initialize(); return executor; } }
如果只是简单的参数配置,那么直接在配置文件中加入如下配置即可
# 多线程配置 spring: task: execution: pool: core-size: 8 max-size: 256 keep-alive: 60000 queue-capacity: 256 thread-name-prefix: test
注意,以上通过yaml配置的方式,需要在启动类上加上多线程的启动注解。
// 通过注解启用异步任务 @EnableAsync @SpringBootApplication public class DbpmsApplication { public static void main(String[] args) { SpringApplication.run(DbpmsApplication.class, args); } }
3 使用多线程
service层
public interface Test{ // 不能有返回值,如果需要返回值需要callback方法 void saveObject(String str); }
service实现层
// 注解不再是@Override而是@Async @Async public void saveObject(String str){ // 打印线程名,看是否开启了多线程 String tName=Thread.currentThread().getName(); System.err.println("调用的线程名字:"+tName); // 可以在下方添加保存数据库操作 }
测试类
@Test void testMd503() { sysLogService.saveObject("张三"); sysLogService.saveObject("李四"); sysLogService.saveObject("王五"); sysLogService.saveObject("赵六"); }
打印结果
如果不通过@Async注解的方式声明并创建多线程,也可以直接通过注入的ThreadPoolTaskExecutor类的execute方法来创建多线程,如下所示。
@RestController @RequestMapping("/test") public class ThreadPoolController { @Autowired private SysLogService sysLogService; // 注入线程池类 @Autowired private ThreadPoolTaskExecutor executor; @GetMapping("/test") public Results test(){ // 线程异步导入数据库,会异步开始执行新增方法,同时原线程不会等待,继续执行。实现了异步操作。 executor.execute(() -> sysLogService.saveObject("张三");); Results results = Results.success(); return results; } }