当前位置: 首页 > news >正文

Java 多线程之@Async

SpringBoot 中使用 @Async

使用 @Async 注解步骤

  • 添加 @EnableAsync 注解。在主类上或者 某个类上,否则,异步方法不会生效 添加 @Async
  • 注解。在异步方法上添加此注解。异步方法不能被 static 修饰需要自定义线程池,则可以配置线程池

1. 配置异步执行:在Spring Boot应用程序的主类上添加@EnableAsync注解,以启用异步执行。通常,主类是带有public static void main(String[] args)方法的类。

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

2. 配置一个TaskExecutor bean。Spring Boot提供了默认的SimpleAsyncTaskExecutor,但您也可以根据需要配置自定义的执行器。例如,您可以在application.properties或application.yml中添加以下配置:

spring:task:execution:pool:# 最大线程数max-size: 16# 核心线程数core-size: 16# 存活时间keep-alive: 10s# 队列大小queue-capacity: 100# 是否允许核心线程超时allow-core-thread-timeout: true# 线程名称前缀thread-name-prefix: async-task-

3. 异步方法:在您的服务类或任何其他组件中,使用@Async注解标记要异步执行的方法。

package com.xkcoding.task.Controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.concurrent.*;
import java.util.function.BiConsumer;@Service
@Slf4j
public class MyAsyncService {private HashMap<String, String> stringStringHashMap = null;@Asyncpublic void executeAsyncTask() {// 模拟耗时任务try {// 业务HashMap<String, String> add = add();} catch (Exception e) {Thread.currentThread().interrupt();}System.out.println(Thread.currentThread().getName()+"executeAsyncTask异步任务完成");}
  • @Async适应自定义线程池
  • @Async 底层原理:就是通过线程池创建一个线程,然后去执行业务逻辑。
  • @Async 注解会应用默认线程池SimpleAsyncTaskExecutor

TaskExecutor bean,以定义您的线程池配置

@Configuration
@Order(-1)
public class CustomThreadPoolConfig {@Bean("customTaskExecutor")public ThreadPoolTaskExecutor customTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);   //核心线程数目executor.setMaxPoolSize(20);   //指定最大线程数executor.setQueueCapacity(50);   //队列中最大的数目executor.setThreadNamePrefix("custom-async-");; //线程名称前缀//rejection-policy:当pool已经达到max size的时候,如何处理新任务//CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());    //对拒绝task的处理策略executor.setKeepAliveSeconds(60);  //线程空闲后的最大存活时间executor.setWaitForTasksToCompleteOnShutdown(true);executor.setAwaitTerminationSeconds(60);executor.initialize();  //加载return executor;}
}

异步调用:

public class MyAsyncService {private HashMap<String, String> stringStringHashMap = null;
//    @Autowired
//    ThreadPoolTaskExecutor customTaskExecutor;@Async("customTaskExecutor")public void executeAsyncTask() {//customTaskExecutor.execute(this::add);// Future<HashMap<String, String>> future = customTaskExecutor.submit(this::add);
}

execute方法分析:
1、当执行方式是execute时,可以看到堆栈异常的输出
原因:ThreadPoolExecutor.runWorker()方法中,task.run(),即执行我们的方法,如果异常的话会throw x;所以可以看到异常。
2、当执行方式是submit时,堆栈异常没有输出。但是调用Future.get()方法时,可以捕获到异常
原因:ThreadPoolExecutor.runWorker()方法中,task.run(),其实还会继续执行FutureTask.run()方法,再在此方法中c.call()调用我们的方法,
如果报错是setException(),并没有抛出异常。当我们去get()时,会将异常抛出。
3、不会影响线程池里面其他线程的正常执行
4、线程池会把这个线程移除掉,并创建一个新的线程放到线程池中
当线程异常,会调用ThreadPoolExecutor.runWorker()方法最后面的finally中的processWorkerExit(),会将此线程remove,并重新addworker()一个线程。

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

submit方法分析:
1、将传进来的任务封装成FutureTask,同样走execute的方法调用,然后直接返回FutureTask。
2、开始执行任务,新增或者获取一个线程去执行任务(比如刚开始是新增coreThread去执行任务)。
3、执行到task.run()时,因为是FutureTask,所以会去调用FutureTask.run()。
4、在FutureTask.run()中,c.call()执行提交的任务。如果抛出异常,并不会throw x,而是setException()保存异常。
5、当我们阻塞获取submit()方法结果时get(),才会将异常信息抛出。当然因为runWorker()没有抛出异常,所以并不会删除线程。

在这里插入图片描述

相关文章:

Java 多线程之@Async

SpringBoot 中使用 Async 使用 Async 注解步骤&#xff1a; 添加 EnableAsync 注解。在主类上或者 某个类上&#xff0c;否则&#xff0c;异步方法不会生效 添加 Async注解。在异步方法上添加此注解。异步方法不能被 static 修饰需要自定义线程池&#xff0c;则可以配置线程池…...

代码随想录day38 动态规划6

题目&#xff1a;322.零钱兑换 279.完全平方数 139.单词拆分 多重背包 背包总结 需要重做&#xff1a;322&#xff0c;139 322. 零钱兑换 思路&#xff1a;零钱&#xff0c;可取多次-》完全背包。 注意&#xff1a; 五部&#xff1a; 1.dp[j]:价值为j的时候&#xff0c;最…...

LabVIEW无标题的模态VI窗口的白框怎么去除?

在LabVIEW中&#xff0c;如果你遇到无标题的模态&#xff08;modal&#xff09;VI窗口显示有一个白框&#xff0c;通常是由于VI界面的一些属性或者控件设置问题导致的。为了去除这个白框&#xff0c;可以尝试以下几种方法&#xff1a; 1. 检查VI窗口属性设置 确保你的VI窗口属…...

iOS - 原子操作

在 Objective-C 运行时中&#xff0c;原子操作主要通过以下几种方式实现&#xff1a; 1. 基本原子操作 // 原子操作的基本实现 #if __has_feature(c_atomic)#define OSAtomicIncrement32(p) __c11_atomic_add((_Atomic(int32_t) *)(p), 1, __ATOMIC_RELAXED) #define …...

Go语言的语法

Go语言入门与实战 引言 在当今的开发环境中&#xff0c;随着互联网的快速发展&#xff0c;程序员们面临着越来越复杂的系统需求。针对这些需求&#xff0c;Go语言&#xff08;又称Golang&#xff09;作为一种新的编程语言应运而生。Go语言由Google开发&#xff0c;它具有简单…...

【MySQL 保姆级教学】用户管理和数据库权限(16)

数据库账户管理是指对数据库用户进行创建、修改和删除等操作&#xff0c;以控制用户对数据库的访问权限。通过账户管理&#xff0c;可以设置用户名、密码、主机地址等信息&#xff0c;确保数据库的安全性和可控性。例如&#xff0c;使用 CREATE USER 创建用户&#xff0c;ALTER…...

什么是 ES6 “模板语法” ?

ES6 提出了“模板语法”的概念。在 ES6 以前&#xff0c;拼接字符串是很麻烦的事情 var name css var career coder! var hobby [coding ,"writing] var finalString my name is name &#xff0c;I work as a career I love hobby[0] and hobby[1]仅仅几…...

[项目实战2]贪吃蛇游戏

目录 贪吃蛇游戏&#xff1a;&#xff1a; 一、游戏效果及功能实现&#xff1a; 1.规则 ​​​​​​​ ​​​​​​​ ​​​​​​​ 2.基本功能实现 ​​​​​​​ ​​​​​​​ ​​​​​​​ 3.技术要点 ​​​​​​​…...

关于FPGA中添加FIR IP核(采用了GOWIN EDA)

文章目录 前言一、IP核二、MATLAB文件三、导出系数COE文件1.设计滤波器2.用官方的matlab代码或者直接用文本文件 四、进行模块化设计源文件 前言 FIR滤波器的特点是其输出信号是输入信号的加权和&#xff0c;权值由滤波器的系数决定。每个系数代表了滤波器在特定延迟位置上的“…...

1. 使用springboot做一个音乐播放器软件项目【前期规划】

背景&#xff1a; 现在大部分音乐软件都是要冲会员才可以无限常听的。对于喜欢听音乐的小伙伴&#xff0c;资金又比较紧张&#xff0c;是那么的不友好。作为程序员的我&#xff0c;也是喜欢听着歌&#xff0c;敲着代码。 最近就想做一个音乐播放器的软件&#xff0c;在内网中使…...

【Dify】Dify自定义模型设置 | 对接DMXAPI使用打折 Openai GPT 或 Claude3.5系列模型方法详解

一、Dify & DMXAPI 1、Dify DIFY&#xff08;Do It For You&#xff09;是一种自动化工具或服务&#xff0c;旨在帮助用户简化操作&#xff0c;减少繁琐的手动操作&#xff0c;提升工作效率。通过DIFY&#xff0c;用户能够快速完成任务、获取所需数据&#xff0c;并且可以…...

【Rust自学】10.8. 生命周期 Pt.4:方法定义中的生命周期标注与静态生命周期

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 10.8.1. 方法定义中的生命周期标注 还记得在上一篇文章 10.7. 生命周期 Pt.3 中所提到的省略生命周期的三条规则吗&#xff1a; 规则1&…...

121 买入股票的最佳时机

思路1&#xff1a; 买的那天一定是卖的那天之前的最小值。 每到一天&#xff0c;维护那天之前的最小值即可。 假设第一天是最小值&#xff0c;最大值初始化为0&#xff0c;当以后某天的价格小于最小值时&#xff0c;将最小值更新 当天价格大于最小值&#xff0c;说明有利可图…...

PID学习资料

TI公司的CONTROLSUITE https://www.ti.com.cn/tool/cn/CONTROLSUITE学点PID专栏-小麦大叔PID控制器算法系列TI公开培训(中文字幕) 电机控制&#xff0c;PI控制器&#xff0c;PID控制器和现场定向控制 书籍&#xff1a; Advanced PID Control先进PID控制及其MATLAB仿真Practic…...

采用标准化的方式开展设计-研发中运用设计模式

概述 实现规范化、标准化的引导式设计&#xff0c;以业务需求为输入&#xff0c;识别业务特点&#xff0c;并通过引导式设计&#xff0c;找到最适合的设计模式、具体方案&#xff0c;汇总成为应用的设计&#xff0c;拉齐各应用的设计一的致性。 采用标准化的方式开展设计…...

【Linux系列】并发与顺序执行:在 Linux 脚本中的应用与选择

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

Scala语言的数据库交互

Scala语言的数据库交互 引言 在当今互联网应用的开发中&#xff0c;数据库几乎是每一个应用程序中不可或缺的一部分。选择合适的编程语言和工具与数据库进行交互&#xff0c;对于提升开发效率和应用性能至关重要。Scala作为一种现代的多范式编程语言&#xff0c;结合了面向对…...

字节青训十五题-Java-数字字符串格式化

问题 问题描述 小M在工作时遇到了一个问题&#xff0c;他需要将用户输入的不带千分位逗号的数字字符串转换为带千分位逗号的格式&#xff0c;并且保留小数部分。小M还发现&#xff0c;有时候输入的数字字符串前面会有无用的 0&#xff0c;这些也需要精简掉。请你帮助小M编写程…...

搭建一个本地轻量级且好用的学习TypeScript语言的环境

需求说明 虽然 TypeScript 的在线 Playground 很方便 https://www.tslang.com.cn/play/&#xff0c;但毕竟是在浏览器中使用&#xff0c;没有本地的 IDE 那么顺手。所以我想搭建一个本地类似 Playground 的环境&#xff0c;这样在学习 TypeScript 的过程中&#xff0c;可以更方…...

apex安装

安装过程复杂曲折&#xff0c;网上说的很多办法&#xff0c;貌似成功了&#xff0c;实际还是没起作用。 先说成功过程&#xff0c;执行下面命令&#xff0c;安装成功&#xff08;当然&#xff0c;前提是你要先配置好编译环境&#xff09;&#xff1a; &#xff08;我的环境&a…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...