Spring Boot注解之@Async和自定义线程池
前言
我们在学习线程池的时候,都知道线程池的核心线程数、最大线程数、线程工厂等核心参数非常重要,故熟记于心。但是有些工作五六年的攻城狮可能说不出来怎么初始化一个全局线程池,以在不同场景使用;所以,本文基于Spring Boot的异步注解@Async自定义全局线程池。如果是这方面的老铁,请绕道而行,这里都是雕虫小技。
maven坐标
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
自定义线程池
核心线程数和最大线程数等参数可以在配置文件中定义,这里为了简单,就直接赋值了。
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.*;
/**
* @Author: Wiener
* @Date: 2022/1/8 19:57
*/
@Configuration
public class AsyncTaskConfig {
// 包括corePoolSize线程在内,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁
@Bean("first-executor")
public Executor firstExecutor() {
ThreadFactory guavaFactory = new ThreadFactoryBuilder().setNameFormat("first-executor").build();
int curSystemThreads = Runtime.getRuntime().availableProcessors() * 2;
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(curSystemThreads, 32,
30L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(), guavaFactory);
threadPool.allowsCoreThreadTimeOut();
return threadPool;
}
//my-task用于指定线程池名字
@Bean("my-executor")
public Executor myExecutor() {
ThreadFactory guavaFactory = new ThreadFactoryBuilder().setNameFormat("my-executor").build();
int curSystemThreads = Runtime.getRuntime().availableProcessors() * 2;
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(curSystemThreads, 32,
30L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(), guavaFactory);
threadPool.allowsCoreThreadTimeOut();
return threadPool;
}
}
使用@Async注解创建线程任务
Spring为任务调度与异步方法执行提供了注解@Async支持,通过在方法上标注@Async注解,可使得方法被异步调用。在需要异步执行的方法上加入@Async注解,并指定使用的线程池,当然可以不指定,直接写@Async。
service定义如下:
/**
* 指定pool
* @Author: Wiener
* @Date: 2022/1/8 19:59
*/
public interface AsyncTaskService {
void executeAsyncTask(Integer i);
void executeMyTask(Integer i);
}
实现类如下:
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
/**
* @Author: Wiener
* @Date: 2022/1/9 12:33
*/
@Slf4j
@Service
public class AsyncTaskServiceImpl implements AsyncTaskService {
@Async("first-executor")
@Override
public void executeAsyncTask(Integer i) {
System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("end executeAsync");
}
@Async("my-executor")
@Override
public void executeMyTask(Integer i) {
System.out.println("---线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("---end executeAsync");
}
}
修改启动类和创建测试类
在启动类添加注解@EnableAsync,以支持异步操作。然后,创建一个controller:
import com.swagger.demo.service.AsyncTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 测试线程池
*/
@Slf4j
@RestController
@RequestMapping("/pool")
public class GuavaController {
@Autowired
private AsyncTaskService asyncTaskService;
@PostMapping("asyncTaskTest")
public void asyncTaskTest() {
// 请求参数写为固定值
asyncTaskService.executeAsyncTask(1);
asyncTaskService.executeMyTask(200);
System.out.println("All tasks finished.");
}
}
启动Spring Boot服务后,请求如上API,在控制台可以看到如下日志:
线程first-executor 执行异步任务:1
All tasks finished.
---线程my-executor 执行异步任务:200
end executeAsync
---end executeAsync
从执行结果来看,我们配置的两个执行器都成功了。
小结|@Async的使用方法
在使用@Async注解的时候,有以下几点需要注意,
- 返回值:若不需要返回值,则直接设置方法返回值为void;若需要,则返回值用AsyncResult或者CompletableFuture承接。
- 自定义执行器,例如:@Async("theGivenExecutor")。
- 如何开启异步:
@Async注解必须在不同类间调用,如 A类—>B类.methodC()(@Async添加在B类的方法methodC上)。若在同一个类中进行方法嵌套调用,会变同步执行,例如:A类.methodB()—>A类.@Async methodC()。 - @Async加到类上,表示这个类的所有方法都是异步执行,并且方法上的注解会覆盖类上的注解。慎用此种使用注解的方式!
老铁们, 因个人能力有限,难免有瑕疵,如果发现bug或者有更好的建议,那么请在文章下方留言!
Reference
https://www.jianshu.com/p/832f2b162450
Spring Boot注解之@Async和自定义线程池的更多相关文章
- 使用@Async注解创建多线程,自定义线程池
说明 使用@Async注解创建多线程非常的方便,还可以通过配置,实现线程池.比直接使用线程池简单太多.而且在使用上跟普通方法没什么区别,加上个@Async注解即可实现异步调用. 用法 AsyncTas ...
- 【快学springboot】10.使用@Async注解创建多线程,自定义线程池
说明 使用@Async注解创建多线程非常的方便,还可以通过配置,实现线程池.比直接使用线程池简单太多.而且在使用上跟普通方法没什么区别,加上个@Async注解即可实现异步调用. 用法 AsyncTas ...
- 多线程使用@Async注解创建多线程,自定义线程池
转载自博客https://www.jianshu.com/p/7ac04a501eba
- Spring Boot中使用@Async的时候,千万别忘了线程池的配置!
上一篇我们介绍了如何使用@Async注解来创建异步任务,我可以用这种方法来实现一些并发操作,以加速任务的执行效率.但是,如果只是如前文那样直接简单的创建来使用,可能还是会碰到一些问题.存在有什么问题呢 ...
- spring boot / cloud (四) 自定义线程池以及异步处理@Async
spring boot / cloud (四) 自定义线程池以及异步处理@Async 前言 什么是线程池? 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线 ...
- Spring Boot使用@Async实现异步调用:自定义线程池
前面的章节中,我们介绍了使用@Async注解来实现异步调用,但是,对于这些异步执行的控制是我们保障自身应用健康的基本技能.本文我们就来学习一下,如果通过自定义线程池的方式来控制异步调用的并发. 定义线 ...
- spring boot自定义线程池以及异步处理
spring boot自定义线程池以及异步处理@Async:什么是线程池?线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使 ...
- SpringCloud 微服务中 @Async 注解自定义线程池 引发的aop 问题
背景 在 使用springCloud 的@Async注解来做异步操作时,想自定义其线程池. 引发问题 自定义完线程池后,发现代码里并没有使用自定义线程池里的线程,于是新建一个demo工程,一样的配置代 ...
- Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用
多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程. 一.ThreadPoolTaskExecutor ...
- Spring Boot 2.X(十):自定义注册 Servlet、Filter、Listener
前言 在 Spring Boot 中已经移除了 web.xml 文件,如果需要注册添加 Servlet.Filter.Listener 为 Spring Bean,在 Spring Boot 中有两种 ...
随机推荐
- mysql安装以及2059 - Authentication plugin 'caching_sha2_password' cannot be loaded:报错的解决办法
2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(../Frameworks/caching_ ...
- Open-Sora 2.0 重磅开源!
潞晨科技正式推出 Open-Sora 2.0 -- 一款全新开源的 SOTA 视频生成模型,仅 20 万美元(224 张 GPU)成功训练商业级 11B 参数视频生成大模型.开发高性能的视频生成模型通 ...
- 如何编写Kubernetes的YAML(一)
什么是API对象 作为一个集群操作系统,Kubernetes 归纳总结了 Google 多年的经验,在理论层面抽象出了很多个概念,用来描述系统的管理运维工作,这些概念就叫做"API 对象&q ...
- Dockerfile 语法与常用命令
转发请注明出处: 一.Dockerfile 核心语法规则 指令大写:所有指令必须大写(如 FROM, RUN) 顺序执行:指令按顺序从上到下执行 分层构建:每条指令生成一个镜像层,修改上层不会影响下层 ...
- 使用Avalonia/C#构建一个简易的跨平台MCP客户端
前言 前几天介绍了在C#中构建一个MCP客户端. 最近正在学习Avalonia,所以就想用Avalonia实现一个简易的跨平台MCP客户端.接入别人写的或者自己写的MCP服务器就可以利用AI做很多有意 ...
- 数据、信息、知识、智慧:AI时代我们该如何思考?
时代的浪潮滚滚向前,AI技术的演进正悄然改变着我们认知世界和创造价值的方式.从数据.信息到知识.智慧,从大数据到大模型,从单一智能体到多智能体协作,这是一场深刻的认知革命,也是生产力解放的新纪元. A ...
- Windows核心编程 进程与线程
进程 Windows作为多任务操作系统,允许多个程序同时在系统中运行.这些程序被称为进程,进程运行在一片独立的空间中,受到操作系统保护,操作系统的很多资源都是围绕着进程来进行分配,可以理解为操作系统维 ...
- 『Plotly实战指南』--饼图绘制基础篇
在数据可视化的世界里,饼图是一种直观且广泛使用的图表类型. 它能够将数据各个部分占整体的比例关系清晰地展现出来,适用于诸如市场占有率分析.调查结果分布.预算分配等多个领域. 饼图以扇形面积比例直观展示 ...
- .NET多线程编程之CountdownEvent使用
简单来说,使用这个类可以让主线程等待子线程都完成任务之后才执行任务 1 static void Main(string[] args) 2 { 3 ///子任务的数量 4 CountdownEvent ...
- Windows 左ctrl和左alt键互换
reg代码 Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyb ...