• spring boot 中的异步@Async


    spring boot 开启异步调用

    1、启动类上添加@EnableAsync注解,表示启动异步

    2、在具体实现异步的方法上添加@Async注解

    1. package com.example.demo;
    2. import org.springframework.boot.SpringApplication;
    3. import org.springframework.boot.autoconfigure.SpringBootApplication;
    4. import org.springframework.scheduling.annotation.EnableAsync;
    5. @SpringBootApplication
    6. @EnableAsync
    7. public class DemoApplication {
    8. public static void main(String[] args) {
    9. SpringApplication.run(DemoApplication.class, args);
    10. }
    11. }
    1. package com.example.demo;
    2. import org.springframework.scheduling.annotation.Async;
    3. import org.springframework.stereotype.Component;
    4. /**
    5. * @Description: TODO
    6. * @author: sl
    7. * @date: 2024年05月30日 21:55
    8. */
    9. @Component
    10. public class DemoController {
    11. /**
    12. * Async相当于是方法级别的线程,本身没有自定义线程池更加灵活
    13. * 相当于是每进来一个请求就开启一个线程,超过核心线程数小于最大线程数放入队列,
    14. * 队列满了,继续创建线程直至达到最大线程数
    15. * @throws InterruptedException
    16. */
    17. @Async
    18. public void testSync() throws InterruptedException {
    19. Thread.sleep(2000);
    20. System.out.println("异步执行成功");
    21. }
    22. }

    测试执行 

    1. package com.example.demo;
    2. import org.junit.jupiter.api.Test;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.boot.test.context.SpringBootTest;
    5. @SpringBootTest
    6. class DemoApplicationTests {
    7. @Autowired
    8. private DemoController demoController;
    9. @Test
    10. void contextLoads() throws InterruptedException {
    11. demoController.testSync();
    12. System.out.println("主线程执行");
    13. Thread.sleep(4000);
    14. }
    15. }

    执行结果 

    执行原理

    SpringBoot会默创建了一个线程池,使用这里面的线程来执行异步调用,在项目中使用

    手动创建线程池异步调用 

    常用线程池创建以及弊端

    Executors 是一个 Java 中的工具类。提供四种线程池创建方式,工厂方法来创建不同类型的线程池。Executors 的创建线程池的方法,创建出来的线程池都实现了ExecutorService 接口,

    1.newFiexedThreadPool(int Threads):创建固定数目线程的线程池。
    2.newCachedThreadPool():创建一个可缓存的线程池,调用 execute将重用以前构造的线程(如果线程可用)。如果没有可用的线程,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
    3.newSingleThreadExecutor() 创建一个单线程化的 Executor。
    4.newScheduledThreadPool(int corePoolSize) 创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代 Timer 类

    不建议大家使用Executors这个类来创建线程池呢,阿里开发手册这样定义:
    强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式

    Executors 返回的线程池对象的弊端如下:

    1) FixedThreadPool 和 SingleThreadPool:

    允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM

    2) CachedThreadPool 和 ScheduledThreadPool:

    允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程,从而导致 OOM

    使用常见的三种线程池创建方式,单一、可变、定长都有一定问题,原因是 FixedThreadPool 和 SingleThreadExecutor 底层都是用LinkedBlockingQueue 实现的,这个队列最大长度为 Integer.MAX_VALUE,容易导致 OOM
    所以实际生产一般自己通过 ThreadPoolExecutor 的 7 个参数,自定义线程池

    spring boot创建线程池 

    springboot创建线程池,Spring提供的对ThreadPoolExecutor封装的线程池ThreadPoolTaskExecutor,直接使用注解启用。
    Async相当于是方法级别的线程,本身没有自定义线程池更加灵活

    1. package com.example.demo.config;
    2. import org.springframework.context.annotation.Bean;
    3. import org.springframework.context.annotation.Configuration;
    4. import org.springframework.core.task.TaskExecutor;
    5. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    6. import java.util.concurrent.ThreadPoolExecutor;
    7. /**
    8. * @Description: TODO
    9. * @author: sl
    10. * @date: 2024年05月30日 22:37
    11. */
    12. @Configuration
    13. public class MyPoolConfig {
    14. @Bean
    15. public TaskExecutor taskExecutor(){
    16. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    17. //设置核心线程数
    18. executor.setCorePoolSize(10);
    19. //设置最大线程数
    20. executor.setMaxPoolSize(15);
    21. //设置队列容量
    22. executor.setQueueCapacity(20);
    23. //设置线程活跃时间(秒)
    24. executor.setKeepAliveSeconds(60);
    25. //设置默认线程名称
    26. executor.setThreadNamePrefix("1111-");
    27. //设置拒绝策略
    28. executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    29. //等待所有任务结束后再关闭线程池
    30. executor.setWaitForTasksToCompleteOnShutdown(true);
    31. return executor;
    32. }
    33. }

    在Async中指定线程池

    1. package com.example.demo;
    2. import org.springframework.scheduling.annotation.Async;
    3. import org.springframework.stereotype.Component;
    4. /**
    5. * @Description: TODO
    6. * @author: sl
    7. * @date: 2024年05月30日 21:55
    8. */
    9. @Component
    10. public class DemoController {
    11. /**
    12. * Async相当于是方法级别的线程,本身没有自定义线程池更加灵活
    13. * 相当于是每进来一个请求就开启一个线程,超过核心线程数小于最大线程数放入队列,
    14. * 队列满了,继续创建线程直至达到最大线程数
    15. * @throws InterruptedException
    16. */
    17. @Async("taskExecutor")
    18. public void testSync() throws InterruptedException {
    19. System.out.println(Thread.currentThread().getName());
    20. Thread.sleep(2000);
    21. System.out.println("异步执行成功");
    22. }
    23. }

    执行结果:

  • 相关阅读:
    13、封装SqlSessionUtils工具类并测试功能
    Chrom谷歌浏览器f12打开开发者模式发现无法看到network的请求
    ROS 学习应用篇(九)ROS中launch文件的实现
    Python使用MySQL,无记录则插入,有记录则更新 - ON DUPLICATE KEY UPDATE
    jquery之Dom操作
    【sass】 中使用 /deep/ 修改 elementUI 组件样式报错
    2022 WAIC 闭幕,融云提供分论坛元宇宙直播技术支持
    2024年04月IDE流行度最新排名
    运行手写数字识别例程出现cuDNN Error: cudnnConvolutionForward failed
    【AI视野·今日NLP 自然语言处理论文速览 第八十二期】Tue, 5 Mar 2024
  • 原文地址:https://blog.csdn.net/m0_65775063/article/details/139331246