spring boot 中的异步@Async

spring boot 开启异步调用

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

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

java 复制代码
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}
java 复制代码
package com.example.demo;


import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * @Description: TODO
 * @author: sl
 * @date: 2024年05月30日 21:55
 */
@Component
public class DemoController {

     /**
     *  Async相当于是方法级别的线程,本身没有自定义线程池更加灵活
     *  相当于是每进来一个请求就开启一个线程,超过核心线程数小于最大线程数放入队列,
     *  队列满了,继续创建线程直至达到最大线程数
     * @throws InterruptedException
     */
    @Async
    public void testSync() throws InterruptedException {
        Thread.sleep(2000);
        System.out.println("异步执行成功");
    }
}

测试执行

java 复制代码
package com.example.demo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    private DemoController demoController;

    @Test
    void contextLoads() throws InterruptedException {
        demoController.testSync();
        System.out.println("主线程执行");
        Thread.sleep(4000);
    }

}

执行结果

执行原理

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相当于是方法级别的线程,本身没有自定义线程池更加灵活

java 复制代码
package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Description: TODO
 * @author: sl
 * @date: 2024年05月30日 22:37
 */
@Configuration
public class MyPoolConfig {
    @Bean
    public TaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心线程数
        executor.setCorePoolSize(10);
        //设置最大线程数
        executor.setMaxPoolSize(15);
        //设置队列容量
        executor.setQueueCapacity(20);
        //设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        //设置默认线程名称
        executor.setThreadNamePrefix("1111-");
        //设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }

}

在Async中指定线程池

java 复制代码
package com.example.demo;


import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * @Description: TODO
 * @author: sl
 * @date: 2024年05月30日 21:55
 */
@Component
public class DemoController {

    /**
     *  Async相当于是方法级别的线程,本身没有自定义线程池更加灵活
     *  相当于是每进来一个请求就开启一个线程,超过核心线程数小于最大线程数放入队列,
     *  队列满了,继续创建线程直至达到最大线程数
     * @throws InterruptedException
     */
    @Async("taskExecutor")
    public void testSync() throws InterruptedException {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(2000);
        System.out.println("异步执行成功");
    }
}

执行结果:

相关推荐
WeiXin_DZbishe2 小时前
基于springboot宠物领养系统-计算机毕设 附源码【课程设计】94217
vue.js·spring boot·python·django·php·课程设计
架构技术专栏2 小时前
Agent 工具调用:从工具声明到执行反馈
前端·人工智能·后端
vx_bisheyuange2 小时前
基于SpringBoot的体育商品推荐系统
spring boot·毕业设计
别动我齐刘海3 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
Wx-bishekaifayuan3 小时前
express皖美特色农产品网售系统53118-计算机课程设计、毕业设计
人工智能·spring boot·后端·python·课程设计·express·旅游
志尊宝4 小时前
Vue3 零基础每日笔记(071):暗黑模式与主题切换——CSS 变量 + Element Plus 暗黑方案
前端·css·笔记·vue·html·前端开发·软件开发
Wx-bishekaifayuan4 小时前
springboot汉中旅游服务平台41442-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
code2cat4 小时前
Java进阶篇之AtomicLongFieldUpdater:把累计额度留在对象字段中
java·cas·并发编程
WeiXin_DZbishe4 小时前
基于springboot城市公交实时运营与调度系统-计算机毕设 附源码【课程设计】66173
java·vue.js·spring boot·后端·python·php·课程设计
泡茶喝茶写代码4 小时前
A股量化数据工程:从 REST 接口到策略信号(第 18 篇):放量缩量异动扫描
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口