当前位置:   article > 正文

springboot 开启一个异步线程_springboot启动一个线程

springboot启动一个线程

使用步骤:

  1. 在Application类上加上 @EnableAsync 注解开启异步
  2. 在被调用的方法上面加上 @Async,也可以直接在类上加此注解,会标识所有方法为异步方法

如下方式会使@Async失效

异步方法使用static修饰

异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类

异步方法不能与被调用的异步方法在同一个类中

类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象

如果使用SpringBoot框架在启动类或配置类中增加@EnableAsync注解

线程池参考链接: https://www.bbsmax.com/A/8Bz8QWwXJx/

一 介绍

工作中经常涉及异步任务,通常是使用多线程技术,比如线程池ThreadPoolExecutor,但使用Executors容易产生OOM,需要手动使用ThreadPoolExecutor创建线程池;在springboot使用 @async 可以实现异步调用,配置线程池参数,可以简单的实现多线程的线程池效果,从而简化开发,避免OOM;

二 异步调用

2.1无返回异步

我们知道同步执行就是按照代码的顺序执行,而异步执行则是无序,在springboot中使用实现异步调用函数非常简单,首先在启动类上加上@EnableAsync 注解;

  1. /**
  2. * @Author lsc
  3. * <p> </p>
  4. */
  5. @SpringBootApplication
  6. @EnableAsync
  7. public class AsyncRunApp {
  8. public static void main(String[] args) {
  9. SpringApplication.run(AsyncRunApp.class, args);
  10. }
  11. }

其次,在函数上标上@sync注解,表示异步调用

  1. @Async
  2. public void taskOne() throws Exception {
  3. System.out.println("任务一");
  4. }
  5. @Async
  6. public void taskTwo() throws Exception {
  7. System.out.println("任务二");
  8. }

测试代码

  1. @Autowired
  2. Task task;
  3. @Test
  4. public void test() throws Exception {
  5. task.taskOne();
  6. task.taskTwo();
  7. }

如果按照同步执行逻辑会先执行任务一,然后再执行任务二,如果是异步执行,则无序,可能任务一先执行,也可能任务二先执行;

2.2 有返回值回调

有时候要知道任务是否执行完成,再继续做其它的业务逻辑,就需要使用到Future接口,其含义是在执行异步任务后会给一个回调函数,我们只要设置回调信息,就可以知道任务是否正确执行完成;我们对异步函数,添加 Future 返回值类型,使用 new AsyncResult<>() 设置回调信息;

  1. @Component
  2. public class Task {
  3. @Async
  4. public Future<String> taskOne() throws Exception {
  5. System.out.println("任务一");
  6. return new AsyncResult<>("任务一执行完成");
  7. }
  8. @Async
  9. public Future<String> taskTwo() throws Exception {
  10. System.out.println("任务二");
  11. return new AsyncResult<>("任务二执行完成");
  12. }
  13. }

测试代码如下, 等待2个任务全部完成后就打印出返回值信息

  1. @Autowired
  2. Task task;
  3. @Test
  4. public void test() throws Exception {
  5. Future<String> str1 = task.taskOne();
  6. Future<String> str2 = task.taskTwo();
  7. while (true){
  8. // 如果任务都做完就执行如下逻辑
  9. if (str1.isDone() && str2.isDone()){
  10. System.out.println(str1.get()+":"+str2.get());
  11. break;
  12. }
  13. }
  14. }

执行输出

  1. 任务二
  2. 任务一
  3. 任务一执行完成:任务二执行完成

 

三 线程池

在异步掉用中使用的@Async 注解,默认的线程池大小如下;

  1. # 核心线程数
  2. spring.task.execution.pool.core-size=8
  3. # 最大线程数
  4. spring.task.execution.pool.max-size=16
  5. # 空闲线程存活时间
  6. spring.task.execution.pool.keep-alive=60s
  7. # 是否允许核心线程超时
  8. spring.task.execution.pool.allow-core-thread-timeout=true
  9. # 线程队列数量
  10. spring.task.execution.pool.queue-capacity=100
  11. # 线程关闭等待
  12. spring.task.execution.shutdown.await-termination=false
  13. spring.task.execution.shutdown.await-termination-period=
  14. # 线程名称前缀
  15. spring.task.execution.thread-name-prefix=task-

一般情况下,我们都需要手动创建线程池,使用 ThreadPoolTaskExecutor 类进行配置;这边设置了线程前缀名称,等下测试时就可以判定是否线程池配置成功;

  1. @Configuration
  2. public class PoolConfig {
  3. @Bean
  4. public TaskExecutor taskExecutor() {
  5. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  6. // 设置核心线程数
  7. executor.setCorePoolSize(10);
  8. // 设置最大线程数
  9. executor.setMaxPoolSize(15);
  10. // 设置队列容量
  11. executor.setQueueCapacity(20);
  12. // 设置线程活跃时间(秒)
  13. executor.setKeepAliveSeconds(60);
  14. // 设置默认线程名称
  15. executor.setThreadNamePrefix("zszxz-");
  16. // 设置拒绝策略
  17. executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
  18. // 等待所有任务结束后再关闭线程池
  19. executor.setWaitForTasksToCompleteOnShutdown(true);
  20. return executor;
  21. }
  22. }

在task类中加上 新的一个方法如下

  1. @Async
  2. public void sayHello(String name) {
  3. LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
  4. }

使用测试类进行测试

  1. @Test
  2. public void testPool() throws Exception {
  3. task.sayHello("公众号:知识追寻者");
  4. }

执行结果如下,日志打印出线程名称为zszxz-1;

有时候,一个项目中如果配置了多个线程池,如下格式

  1. @Bean("pool1")
  2. public TaskExecutor taskExecutor1() {
  3. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  4. //....
  5. return executor;
  6. }
  7. @Bean("pool2")
  8. public TaskExecutor taskExecutor2() {
  9. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  10. //....
  11. return executor;
  12. }
  13. @Bean("pool3")
  14. public TaskExecutor taskExecutor3() {
  15. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  16. //....
  17. return executor;
  18. }

在使用 @Async注解时就需要指明具体使用的线程池,如下格式

  1. @Async("pool1")
  2. public void sayHello1(String name) {
  3. LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
  4. }
  5. @Async("pool2")
  6. public void sayHello1(String name) {
  7. LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
  8. }

源码地址:https://github.com/zszxz/study-springboot

 

参考链接:

https://blog.csdn.net/youku1327/article/details/111406143

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/767501
推荐阅读
相关标签
  

闽ICP备14008679号