基于Spring 框架中的@Async 注解实现异步任务

@Async 是 Spring 框架中的一个注解,用于实现方法级别的异步执行。使用 @Async 可以让你的代码在非当前线程中执行,从而提高应用的并发性能。

1、 启用异步支持

在 Spring 应用的主配置类或任何其他配置类上添加 @EnableAsync 注解来开启异步任务的支持

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



@SpringBootApplication
@EnableAsync
public class Demo2024Application {
    public static void main(String[] args) {
        SpringApplication.run(Demo2024Application.class, args);
    }
}
2、配置异步执行器

默认情况下,Spring 使用一个内置的 SimpleAsyncTaskExecutor。为了更好地控制线程池,你可以自定义一个 ThreadPoolTaskExecutor 并在配置类中声明它。

   import org.springframework.context.annotation.Bean;
   import org.springframework.context.annotation.Configuration;
   import org.springframework.scheduling.annotation.AsyncConfigurer;
   import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

   @Configuration
   public class AppConfig implements AsyncConfigurer {

       @Override
       public Executor getAsyncExecutor() {
           ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
           executor.setCorePoolSize(5);  // 核心线程数
           executor.setMaxPoolSize(10);  // 最大线程数
           executor.setQueueCapacity(200);  // 队列大小
           executor.setThreadNamePrefix("MyExecutor-");  // 线程前缀名称
           executor.initialize();
           return executor;
       }
   }
   
3、标注异步方法

在需要异步执行的方法上添加 @Async 注解。这个方法将不会阻塞当前调用线程,而是立即返回,异步执行任务。


    @Async
    public void testAsyncMethod(){
        log.info("执行Service类的异步方法 start .......");
        // 执行本Service 类的异步方法 sleep 10s 且每2秒输出一下进度
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(2000);
                log.info("执行Service类的异步方法 threadName:{}, progress .......:{}",Thread.currentThread().getName(),i);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("执行Service类的异步方法 end .......");
    }
4、注意事项
  • a、异步方法不能直接在控制器(Controller)层使用,因为它们通常需要返回一个响应给客户端,这与异步方法的无返回行为不兼容
  • b、异步方法不能直接调用同一类中的其他异步方法,否则可能会导致死锁。
    通过测试发现,在同一类中调用其它异步方法,打印出来的线程名 都是同一个线程
    测试如下 在同一controller中
  /**
     * 测试本controller 类的异步方法
     */
    @GetMapping("/testControllerAsync")
    public void testControllerAsync(){
        log.info("testControllerAsyncy,调用方法执行打印 开始 .......");
        log.info("testControllerAsync method threadName:{}",Thread.currentThread().getName());
        // 调用本controller 类的异步方法
        testCurrentControllerAsyncMethod();
        log.info("testControllerAsync,调用方法执行打印 开始 .......");
    }

    @Async
    public void testCurrentControllerAsyncMethod(){
        log.info("执行本controller 类的异步方法 start .......");
        // 执行本controller 类的异步方法 sleep 10s 且每2秒输出一下进度
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(2000);
                log.info("执行本controller 类的异步方法threadName:{}, progress .......:{}",Thread.currentThread().getName(),i);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("执行本controller 类的异步方法 end .......");
    }

调用接口后 输出内容如下 可以看出 调用方法和被调用的异步方法 打印的threadName 是相同的,且调用方法的结束打印是在异步方法执行结束之后执行的,说明异步方法没生效
在这里插入图片描述
测试在同一service中

@Slf4j
@RestController
public class AsyncTestController {
    @Resource
    private AsyncTestService asyncService;
    /**
     * 调用Service 类的方法,然后service再调用同service类中的异步方法
     */
    @GetMapping("/testService")
    public void testService(){
        log.info("testService controller method 打印开始 .......");
        log.info("testService controller method threadName:{}",Thread.currentThread().getName());
        // 调用Service 类的方法,然后service再调用同service类中的异步方法
        asyncService.testServiceMethod();
        log.info("testService controller method 打印开始 .......");
    }
}

@Service
@Slf4j
public class AsyncTestService {

    @Async
    public void testAsyncMethod(){
        log.info("执行Service类的异步方法 start .......");
        // 执行本Service 类的异步方法 sleep 10s 且每2秒输出一下进度
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(2000);
                log.info("执行Service类的异步方法 threadName:{}, progress .......:{}",Thread.currentThread().getName(),i);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("执行Service类的异步方法 end .......");
    }
    
    public void testServiceMethod(){
        log.info("testServiceMethod method start .......");
        log.info("testServiceMethod method threadName:{}",Thread.currentThread().getName());
        // 调用Service正常方法,然后正常方法调用本service中的异步方法
        testAsyncMethod();
        log.info("testServiceMethod method end .......");
    }
}

调用接口后输出内容如下 可以看出 调用方法及service中的方法和被调用的异步方法 打印的threadName 是相同的,且调用方法的结束打印和service中调用的方法的打印是在异步方法执行结束之后执行的,说明异步方法没生效

在这里插入图片描述

5、 正确的调用 如下,
@Slf4j
@RestController
public class AsyncTestController {

    @Resource
    private AsyncTestService asyncService;
    /**
     * 测试service 类的中异步方法
     */
    @GetMapping("/testServiceAsync")
    public void testServiceAsync(){
        log.info("testServiceAsync controller method start .......");
        log.info("testServiceAsync controller method threadName:{}",Thread.currentThread().getName());
        // 调用Service 类的异步方法
        asyncService.testAsyncMethod();
        log.info("testServiceAsync controller method end .......");
    }
 }

@Service
@Slf4j
public class AsyncTestService {

    @Async
    public void testAsyncMethod(){
        log.info("执行Service类的异步方法 start .......");
        // 执行本Service 类的异步方法 sleep 10s 且每2秒输出一下进度
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(2000);
                log.info("执行Service类的异步方法 threadName:{}, progress .......:{}",Thread.currentThread().getName(),i);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("执行Service类的异步方法 end .......");
    }
}

调用后输出如下,可以看出 调用的controller方法 和service中异步方法打印的 线程名称是不相同的,且调用的controller方法的开始打印 及结整打印都是在异步方法打印之前执行的,说明异步方法生效了
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/658704.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WordPress中借助Table of Contents Plus+Widget Options插件,实现仅在文章侧边栏显示文章目录的功能

本文转自博主的个人博客&#xff1a;https://blog.zhumengmeng.work,欢迎大家前往查看。 原文链接&#xff1a;点我访问 序言&#xff1a;今天心血来潮&#xff0c;写了一篇文章&#xff0c;忽然发现自己的文章极少有目录&#xff0c;这对于长文章的阅读来说是十分不利的&#…

Android14 WMS-窗口添加流程(一)-Client端

窗口布局在onCreate方法中通过setContentView(R.layout.xxx)加载&#xff0c;但窗口的显示并不是在wm_on_create_called中, 而是在wm_on_resume_called后&#xff0c;也就是说应用onResume时此窗口是不可见的&#xff0c;真正可见是当此window窗口的mDrawState变化状态从NO_SUR…

2024年社会发展、人文艺术与文化国际会议(ICSDHAC 2024)

2024年社会发展、人文艺术与文化国际会议&#xff08;ICSDHAC 2024&#xff09; 会议简介 2024年国际社会发展、人文、艺术和文化会议&#xff08;ICSDHAC 2024&#xff09;将在广州举行。会议旨在为从事社会发展、人文、艺术和文化研究的专家学者提供一个平台&#xff0c;分…

xjar加密springboot的jar包,并编译为执行程序

场景&#xff1a;当前项目需要进行jar包部署在windows环境和linux环境&#xff0c;并要求使用xjar加密。 1. xjar加密 源码程序自行搜索&#xff0c;这里只介绍加密及运行&#xff0c;运行加密程序&#xff0c;指定jar包&#xff0c;输入密码 2. 加密后的目录 3. go程序编译 …

Vanna使用ollama分析本地MySQL数据库

上一章节中已经实现了vanna的本地运行&#xff0c;但是大模型和数据库都还是远程的&#xff0c;因为也就没办法去训练&#xff0c;这节一起来实现vanna分析本地mysql数据库&#xff0c;因为要使用本地大模型&#xff0c;所以开始之前需要给本地安装好大模型&#xff0c;我这里用…

【数据结构】二叉搜索树——高阶数据结构的敲门砖

目录 树概述 二叉搜索树概述 概念 特性 元素操作 插入 删除 模拟实现 框架 查找 插入 删除 树概述 树——在计算机中是一种很常见的数据结构。 树是一种很强大的数据结构&#xff0c;数据库&#xff0c;linux操作系统管理和windows操作系统管理所有文件的结构就是…

PS教程08

光效 新建一个图层 按住Altdelete将颜色填充完毕。 转换智能对象 作用&#xff1a;我们可以对这个图层无限期修改 接下来找到滤镜-渲染-镜头光晕 选择需要的亮度和镜头类型&#xff0c;点击确定 如果发现位置不太理想&#xff0c;可以直接双击右下角的镜头光晕&#xff0c;…

swagger-ui页面接口的入参出参与代码实体类不一致有差异、swagger请求实体与预期定义不符、swagger参数与实体中参数不一致原因分析

文章目录 一、问题背景二、问题原因及解决方法 一、问题背景 项目集成swagger之后&#xff0c;发现有个接口的请求跟接口对应不上&#xff0c;把其他接口的请求参数放到当前这个请求上了。 如下图&#xff1a;test1接口的请求参数是其他请求的&#xff0c;并不是test1接口的 …

RFID芯片掼蛋牌:高科技与传统玩法结合,游戏体验焕然一新。

火爆“出圈”的掼蛋&#xff0c;是一种玩法相当鲜明的智力游戏。近年来得到了不少的推广和发展&#xff0c;各地举办了各种掼蛋比赛和活动&#xff0c;吸引了大量的参赛者和观众。此外&#xff0c;一些企业和机构也开始将掼蛋作为一种企业文化或者社交活动的方式&#xff0c;通…

无需开孔,安全美观:低功耗微波雷达模块开启宠物喂食器新未来

在快节奏的现代生活中&#xff0c;宠物已成为许多家庭的重要成员。然而&#xff0c;忙碌的主人常常为如何确保宠物按时进食而困扰。近年来&#xff0c;智能家居技术飞速发展&#xff0c;宠物喂食器也逐渐智能化&#xff0c;极大地方便了宠物主人。今天&#xff0c;我们要介绍的…

项目成功的关键要素:进度管理

在项目管理中&#xff0c;进度管理是决定项目成败的关键因素之一。它关乎项目能否在预定的时间范围内高效、准确地完成既定目标。 一、进度管理的重要性 1、时间控制&#xff1a;项目的成功往往与时间的把握息息相关。进度管理能够确保项目在既定的时间框架内有序进行&#x…

MySQL select for update 加锁

背景 当多人操作同一个客户下账号的时候&#xff0c;希望顺序执行&#xff0c;某个时刻只有一个人在操作&#xff1b;当然可以通过引入redis这种中间件实现&#xff0c;但考虑到并发不会很多&#xff0c;所以不想再引入别的中间件。 表结构 create table jiankunking_accoun…

肆拾玖坊FFC模式,社群裂变,股权众筹设计

肆拾玖坊商业模式&#xff0c;白酒新零售体系&#xff0c;众筹合伙模式 坐标&#xff1a;厦门&#xff0c;我是易创客肖琳 深耕社交新零售行业10年&#xff0c;主要提供新零售系统工具及顶层商业模式设计、全案策划运营陪跑等。 联想高管辞职跑去卖酒&#xff0c;6年狂赚30亿&…

手机“本地”也能玩转AI大模型 - 万物皆可AI

友友们&#xff0c;大家好&#xff01;我最近发现一个很有意思的AI项目——MiniCPM-V&#xff0c;可以说它将AI技术的应用推向了一个全新的高度&#xff0c;让我们能够将GPT-4V级的多模态大模型直接部署在我们的手机上&#xff0c;而且完全不需要联网&#xff0c;真正的手机本地…

Unity版本使用情况统计(更新至2024年4月)

UWA发布&#xff5c;本期UWA发布的内容是第十四期Unity版本使用统计&#xff0c;统计周期为2023年11月至2024年4月&#xff0c;数据来源于UWA网站&#xff08;www.uwa4d.com&#xff09;性能诊断提测的项目。希望给Unity开发者提供相关的行业趋势作为参考。 2023年11月 - 2024年…

C++候捷stl-视频笔记1

认识headers、版本、重要资源 STL的核心思想是泛型编程 新式头文件内的组件封装在命名空间std中&#xff1a; using namespace std; using std::cout;或std::vector vec; 旧式头文件内的组件不封装在命名空间std中 注:不建直接使用using namespace xxx&#xff0c;如果使用的…

apexcharts数据可视化之极坐标区域图

apexcharts数据可视化之极坐标区域图 有完整配套的Python后端代码。 本教程主要会介绍如下图形绘制方式&#xff1a; 基础极坐标区域图单色极坐标区域图 基础极坐标区域图 import ApexChart from react-apexcharts;export function BasicPolar() {// 数据序列const series…

深入解析多维数组与主对角线元素之和

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;多维数组的奥秘 二、多维数组的基本概念 1. 定义与创建 2. 维度与形…

Linux服务器安装docker,基于Linux(openEuler、CentOS8)

本实验环境为openEuler系统(以server方式安装)&#xff08;CentOS8基本一致&#xff0c;可参考本文) 目录 知识点实验 知识点 Docker 是一个开源的应用容器引擎。它允许开发者将应用及其所有依赖项打包到一个可移植的容器中&#xff0c;并发布到任何支持Docker的流行Linux或Wi…

歌曲转换成mp3格式超简单!快来试试看

在数字音乐时代&#xff0c;我们经常从各种来源下载或收藏到各种音频文件&#xff0c;但有时这些文件可能并不是我们设备所支持的常见格式&#xff0c;尤其是当我们更倾向于使用MP3格式的时候。因此&#xff0c;对于那些希望统一音乐库格式的人来说&#xff0c;将歌曲转换成mp3…