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 注解步骤: 添加 EnableAsync 注解。在主类上或者 某个类上,否则,异步方法不会生效 添加 Async注解。在异步方法上添加此注解。异步方法不能被 static 修饰需要自定义线程池,则可以配置线程池…...
代码随想录day38 动态规划6
题目:322.零钱兑换 279.完全平方数 139.单词拆分 多重背包 背包总结 需要重做:322,139 322. 零钱兑换 思路:零钱,可取多次-》完全背包。 注意: 五部: 1.dp[j]:价值为j的时候,最…...
LabVIEW无标题的模态VI窗口的白框怎么去除?
在LabVIEW中,如果你遇到无标题的模态(modal)VI窗口显示有一个白框,通常是由于VI界面的一些属性或者控件设置问题导致的。为了去除这个白框,可以尝试以下几种方法: 1. 检查VI窗口属性设置 确保你的VI窗口属…...
iOS - 原子操作
在 Objective-C 运行时中,原子操作主要通过以下几种方式实现: 1. 基本原子操作 // 原子操作的基本实现 #if __has_feature(c_atomic)#define OSAtomicIncrement32(p) __c11_atomic_add((_Atomic(int32_t) *)(p), 1, __ATOMIC_RELAXED) #define …...
Go语言的语法
Go语言入门与实战 引言 在当今的开发环境中,随着互联网的快速发展,程序员们面临着越来越复杂的系统需求。针对这些需求,Go语言(又称Golang)作为一种新的编程语言应运而生。Go语言由Google开发,它具有简单…...
【MySQL 保姆级教学】用户管理和数据库权限(16)
数据库账户管理是指对数据库用户进行创建、修改和删除等操作,以控制用户对数据库的访问权限。通过账户管理,可以设置用户名、密码、主机地址等信息,确保数据库的安全性和可控性。例如,使用 CREATE USER 创建用户,ALTER…...
什么是 ES6 “模板语法” ?
ES6 提出了“模板语法”的概念。在 ES6 以前,拼接字符串是很麻烦的事情 var name css var career coder! var hobby [coding ,"writing] var finalString my name is name ,I work as a career I love hobby[0] and hobby[1]仅仅几…...
[项目实战2]贪吃蛇游戏
目录 贪吃蛇游戏:: 一、游戏效果及功能实现: 1.规则 2.基本功能实现 3.技术要点 …...
关于FPGA中添加FIR IP核(采用了GOWIN EDA)
文章目录 前言一、IP核二、MATLAB文件三、导出系数COE文件1.设计滤波器2.用官方的matlab代码或者直接用文本文件 四、进行模块化设计源文件 前言 FIR滤波器的特点是其输出信号是输入信号的加权和,权值由滤波器的系数决定。每个系数代表了滤波器在特定延迟位置上的“…...
1. 使用springboot做一个音乐播放器软件项目【前期规划】
背景: 现在大部分音乐软件都是要冲会员才可以无限常听的。对于喜欢听音乐的小伙伴,资金又比较紧张,是那么的不友好。作为程序员的我,也是喜欢听着歌,敲着代码。 最近就想做一个音乐播放器的软件,在内网中使…...
【Dify】Dify自定义模型设置 | 对接DMXAPI使用打折 Openai GPT 或 Claude3.5系列模型方法详解
一、Dify & DMXAPI 1、Dify DIFY(Do It For You)是一种自动化工具或服务,旨在帮助用户简化操作,减少繁琐的手动操作,提升工作效率。通过DIFY,用户能够快速完成任务、获取所需数据,并且可以…...
【Rust自学】10.8. 生命周期 Pt.4:方法定义中的生命周期标注与静态生命周期
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 10.8.1. 方法定义中的生命周期标注 还记得在上一篇文章 10.7. 生命周期 Pt.3 中所提到的省略生命周期的三条规则吗: 规则1&…...
121 买入股票的最佳时机
思路1: 买的那天一定是卖的那天之前的最小值。 每到一天,维护那天之前的最小值即可。 假设第一天是最小值,最大值初始化为0,当以后某天的价格小于最小值时,将最小值更新 当天价格大于最小值,说明有利可图…...
PID学习资料
TI公司的CONTROLSUITE https://www.ti.com.cn/tool/cn/CONTROLSUITE学点PID专栏-小麦大叔PID控制器算法系列TI公开培训(中文字幕) 电机控制,PI控制器,PID控制器和现场定向控制 书籍: Advanced PID Control先进PID控制及其MATLAB仿真Practic…...
采用标准化的方式开展设计-研发中运用设计模式
概述 实现规范化、标准化的引导式设计,以业务需求为输入,识别业务特点,并通过引导式设计,找到最适合的设计模式、具体方案,汇总成为应用的设计,拉齐各应用的设计一的致性。 采用标准化的方式开展设计…...
【Linux系列】并发与顺序执行:在 Linux 脚本中的应用与选择
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
Scala语言的数据库交互
Scala语言的数据库交互 引言 在当今互联网应用的开发中,数据库几乎是每一个应用程序中不可或缺的一部分。选择合适的编程语言和工具与数据库进行交互,对于提升开发效率和应用性能至关重要。Scala作为一种现代的多范式编程语言,结合了面向对…...
字节青训十五题-Java-数字字符串格式化
问题 问题描述 小M在工作时遇到了一个问题,他需要将用户输入的不带千分位逗号的数字字符串转换为带千分位逗号的格式,并且保留小数部分。小M还发现,有时候输入的数字字符串前面会有无用的 0,这些也需要精简掉。请你帮助小M编写程…...
搭建一个本地轻量级且好用的学习TypeScript语言的环境
需求说明 虽然 TypeScript 的在线 Playground 很方便 https://www.tslang.com.cn/play/,但毕竟是在浏览器中使用,没有本地的 IDE 那么顺手。所以我想搭建一个本地类似 Playground 的环境,这样在学习 TypeScript 的过程中,可以更方…...
apex安装
安装过程复杂曲折,网上说的很多办法,貌似成功了,实际还是没起作用。 先说成功过程,执行下面命令,安装成功(当然,前提是你要先配置好编译环境): (我的环境&a…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...
