@Async Spring的异步小精灵

一些重要的后台接口,希望加快任务的执行速度,可以考虑 多线程异步执行任务。

@Async是spring框架中十分好用的异步写法:

  1. 在方法上使用该@Async注解,申明该方法是一个异步任务;

  2. 在类上面使用该@Async注解,申明该类中的所有方法都是异步任务;

  3. 使用此注解的方法的类对象,必须是spring管理下的bean对象;

  4. 要想使用异步任务,需要在主类上开启异步配置,即,配置上@EnableAsync注解;

一、SpringBoot使用@Async注解步骤

step1、启动类上使用@EnableAsync注解

@SpringBootApplication
@EnableAsync
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}  

step2、异步方法所在的类注入容器中

 @Componetpublic class Wtt{}

除了@Componet,也可以是@Controller、@RestController、@Service、@Configuration等注解,加入到Ioc容器里。

step3、方法上加上@Async注解

@Servicepublic class Wtt{@Asyncpublic void a() {}
}

二、@Async异步失效 的 两种情况

因为@Async是基于 Aop思想 实现的,所有下面两种情况也会失效。

1、异步方法使用 static 修饰

    @Asyncpublic static void a() {}

2、调用方法 和 异步方法 在同一个类中

当异步方法和调用方法在同一个类中时,是没办法通过Ioc里的bean来执行异步方法的,从而变成同步方法。

如下:

@Component
public class Task {/*** 调异步方法和异步方法在同一个类 @Async执行失败*/public void dotask() {this.taskOne();this.taskTwo();}@Asyncpublic void taskOne() {//执行任务1}@Asyncpublic void taskTwo() {//执行任务2}
}

三、@Async + 自定义线程池

如果 不自定义异步方法 的 线程池, 那么 默认使用 SimpleAsyncTaskExecutor线程池。

SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。因此 并发大的时候会产生严重的性能问题。

Spring 推荐 使用 ThreadPoolTaskExecutor类来创建线程池。
因此 在 SpringBoot 2.0.9 版本及以前,@Async 默认使用的是 SimpleAsyncTaskExecutor;
从 2.1.0 开始,@Async 默认使用的是 ThreadPoolTaskExecutor。

也就是说新版本,其实spring boot默认使用的已经是 ThreadPoolTaskExecutor 线程池了,大家不用再去手动更改默认的线程池,
不过还是可以在 配置文件 更改 ThreadPoolTaskExecutor 的参数。

  • 自定义线程池
package com.wtt.components;import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;@Configuration
public class Whero {@Bean(name = "wheroCreateNewAsyncExecutor")public Executor newAsync() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();//设置核心线程数taskExecutor.setCorePoolSize(10);// 线程池维护线程的最大数量,只有在缓冲队列满了以后才会申请超过核心线程数的线程taskExecutor.setMaxPoolSize(100);//缓存队列taskExecutor.setQueueCapacity(50);//允许的空闲时间,当超过了核心线程数之外的线程在空闲时间到达之后会被销毁taskExecutor.setKeepAliveSeconds(200);//异步方法内部线程名称taskExecutor.setThreadNamePrefix("whero-AsyncExecutor");//拒绝策略taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());taskExecutor.initialize();return taskExecutor;}
}
  • 异步任务
package com.wtt.components;import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;import java.util.concurrent.Future;@Component
@Slf4j
public class Wtt {@Async("wheroCreateNewAsyncExecutor")public Future<String> taskOne() throws Exception {log.info("任务1线程名称 = {}", Thread.currentThread().getName());return new AsyncResult<>("1完成");}@Async("wheroCreateNewAsyncExecutor")public Future<String> taskTwo() throws Exception {log.info("任务2线程名称 = {}", Thread.currentThread().getName());return new AsyncResult<>("2完成");}@Asyncpublic Future<String> taskThere() throws Exception {log.info("任务3线程名称 = {}", Thread.currentThread().getName());return new AsyncResult<>("执行任务3完成");}
}
  • 测试 执行 异步任务
package com.wtt.controller;import com.wtt.components.Wtt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j
public class UsersController {@Autowiredprivate Wtt wtt;@GetMapping("/a1")public int a1() throws Exception {long start = System.currentTimeMillis();wtt.taskOne();wtt.taskTwo();wtt.taskThere();long end = System.currentTimeMillis();log.info("总任务执行结束,总耗时={} 毫秒", end - start);return 0;}
}

输出:

[nio-8886-exec-1] com.wtt.controller.UsersController       : 总任务执行结束,总耗时=11 毫秒
[-AsyncExecutor2] com.wtt.components.Wtt                   : 任务2线程名称 = whero-AsyncExecutor2
[-AsyncExecutor1] com.wtt.components.Wtt                   : 任务1线程名称 = whero-AsyncExecutor1
[-AsyncExecutor3] com.wtt.components.Wtt                   : 任务3线程名称 = whero-AsyncExecutor3

虽然 我们设定的 任务1 和 任务2 配置走 自定义的线程池,任务3 还是走 默认线程池, 但是我们发现 三个 任务走的都是 我们自定义的 线程池。

@Async 是 方法级别 的 异步, 而 CompletableFuture 是 代码级别 的 异步,所以 很多场景下 还是推荐使用 CompletableFuture 进行 异步操作。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LangChain学习之 Question And Answer的操作

1. 学习背景 在LangChain for LLM应用程序开发中课程中&#xff0c;学习了LangChain框架扩展应用程序开发中语言模型的用例和功能的基本技能&#xff0c;遂做整理为后面的应用做准备。视频地址&#xff1a;基于LangChain的大语言模型应用开发构建和评估。 2. Q&A的作用 …

07-使用 JavaScript Promise 并行处理多个请求

使用 JavaScript Promise 并行处理多个请求 笔记分享 在现代Web开发中&#xff0c;处理多个异步请求并行是一个常见需求。JavaScript中的Promise提供了一种强大的机制来管理这些并行操作。本文将详细介绍如何使用Promise.all和Promise.allSettled来实现这一点&#xff0c;并提…

Echarts 中type是value的X轴在设置了interval间隔后没有展示

文章目录 问题分析问题 Echarts中type是value的X轴在设置了interval间隔后没有展示 分析 之前代码是这样写的:axisLabel 属性中设置了 interval ,但未起作用,原因如下 在 ECharts 中,interval 属性是用于类目型(category)轴的刻度间隔设置,并不适用于数值型(value)…

音视频视频点播

视频点播是集音视频采集&#xff0c;编辑&#xff0c;上传&#xff0c;自动化转码处理&#xff0c;媒体资源管理&#xff0c;高效云剪辑处理&#xff0c;分发加速&#xff0c;视频播放于一体的一站式音视频点播解决方案 阿里云视频点播基于阿里云强大的基础设施服务&#xff0c…

解决 clickhouse jdbc 偶现 failed to respond 问题

背景 Clickhouse集群版本为 Github Clickhouse 22.3.5.5&#xff0c; clickhouse-jdbc 版本为 0.2.4。 问题表现 随着业务需求的扩展&#xff0c;基于Clickhouse 需要支持更多任务在期望的时效内完成&#xff0c;于是将业务系统和Clickhouse交互的部分都提交给可动态调整核心…

【西瓜书】1.绪论

1.基本术语 &#xff08;1&#xff09;数据集不带最后一列&#xff1a;样本/示例/特征向量 带最后一列&#xff1a;样例 &#xff08;2&#xff09;表头不带最后一列&#xff1a;属性/特征&#xff0c;属性空间/特征空间/样本空间/输入空间 表头最后一列&#xff1a;标记/输出…

windows上安装MongoDB,springboot整合MongoDB

上一篇文章已经通过在Ubuntu上安装MongoDB详细介绍了MongoDB的各种命令用法。 Ubuntu上安装、使用MongoDB详细教程https://blog.csdn.net/heyl163_/article/details/133781878 这篇文章介绍一下在windows上安装MongoDB&#xff0c;并通过在springboot项目中使用MongoDB记录用户…

Go语言交叉编译

Golang 支持交叉编译&#xff0c; 在一个平台上生成然后再另外一个平台去执行。 以下面代码为例 build ├── main.go ├── go.mod main.go内容 package mainimport "fmt"func main() {fmt.Println("hello world") }windows系统上操作 1.cmd窗口编译…

java新特性--03-1--Stream---Collectors工具类

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.stream 收集Collectors工具类注意区分 Collections工具类 练习1&#xff1a;查找工资大于6000的员工&#xff0c;结果返回为一个List练习2&#xff1a;查找年龄小…

【含项目亮点】小免鲜项目总结

【含项目亮点】小兔鲜项目总结 基础总结 vue3的优势 组合式API,更好的支持TS。速度提高,diff算法重写。按需引入,更好的treeshaking,体积小。数据式响应更优,使用js的proxy替代Object.defineProperty数据响应式系统,更灵活。 vue3使用的是vue-create脚手架工具,vue2使用…

【设计模式】结构型-组合模式

前言 在软件开发中&#xff0c;设计模式是一种被广泛应用的解决问题的方法论。其中&#xff0c;结构性设计模式是一类特别重要的模式&#xff0c;它们用于处理类或对象之间的组合关系&#xff0c;其中之一就是组合模式。组合模式允许客户端统一对待单个对象和对象的组合&#…

结构体(2),链表,共用体

链式数据结构 -- 链表 定义&#xff1a; struct Node { int data; //数据域 --存储要处理的数据 struct Node *next; //指针域&#xff0c;保存地址-- 指向下一个节点 }; //数据域指针域 //节点类型 struct Node n1; struct Node n2; struct Node n3; s1--&…

DeepSort整体流程梳理及匈牙利算法解析

文章目录 算法原理一、主要步骤二、算法流程:三、匈牙利算法:3.1 举例说明匈牙利匹配过程:3.2匈牙利算法中代价矩阵的计算(距离)卡尔曼滤波后面更新。 算法原理 DeepSort核心在于其对目标的外观特征和运动特征的联合使用,以及对目标匹配问题的优化处理。该算法通过融合目…

【前端技术】 ES6 介绍及常用语法说明

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

使用wheelnav.js构建酷炫的动态导航菜单

目录 前言 一、WheelNav是什么 1、项目地址 2、关于开源协议 3、相关目录介绍 二、如何使用wheelnav.js 1、新建html页面 2、设置style样式 3、创建展示元素实现动态导航 三、参数即方法介绍 1、参数列表 2、运行方法 3、实际成果 四、总结 前言 用户体验永远是一…

玩转盲盒潮流:从0到1搭建小程序平台

玩转盲盒潮流并搭建一个从0到1的小程序平台来创作内容是一个充满挑战但有趣的过程。以下是一个步骤指南&#xff0c;帮助你实现这一目标&#xff1a; 1. 市场调研与定位 了解盲盒市场&#xff1a;研究当前盲盒市场的趋势、消费者喜好和成功案例。确定目标用户&#xff1a;明确…

android-jni2

详细的jni调用说明&#xff1a;Android学习--JNI_android jni-CSDN博客 jclass clazz;index;LOGE("开始:%d", "begin");clazz (*env).FindClass("com/changan/incalleventservice/input/NativeAction");//找到对应的java文件jfieldID instanc…

docker-compose 部署rabbitmq 15672打不开

docker-compose 部署rabbitmq 15672打不开 如果docker-compose的rabbitmq镜像后缀不是-management如&#xff1a;3.7.4-management&#xff0c;则需要进入容器中手动启动插件 部署rabbitmq后需要启动插件的命令&#xff1a; rabbitmq-plugins enable rabbitmq_management 一…

软件质量保障——三、四

三、黑盒测试 1.黑盒测试概述 1.1 如何理解黑盒测试&#xff1f; 1.2 黑盒测试有什么特点&#xff1f; 1.3 如何实施黑盒测试&#xff1f; 2. 黑盒测试用例设计和生成方法&#xff08;这里还是要自己找题做&#xff09; 2.1 等价类划分法 步骤&#xff1a; 1.选择划分准…

解释JDBC的作用和连接数据库的步骤

JDBC&#xff08;Java Database Connectivity&#xff09;是Java编程语言中用来执行SQL语句的API。它的主要作用是为Java程序提供连接各种关系型数据库的能力&#xff0c;使得Java开发者能够编写出与数据库进行交互的应用程序。JDBC的作用具体体现在以下几个方面&#xff1a; 数…