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 中有两种 ...
随机推荐
- Elasticsearch搜索引擎学习笔记(三)
索引的一些操作 集群健康 GET /_cluster/health 创建索引 PUT /index_test { "settings": { "index": ...
- 又一国产AI爆火!Manus强势炸场,邀请码申请方法,看这一篇就够了!
3月6日凌晨,一款名为Manus的国产AI产品横空出世,迅速霸榜社交平台热搜.其内测邀请码在二手交易平台被炒至5万元天价,甚至出现标价10万元的卖家,我的个乖乖啊. 究竟是什么让Manus如此火爆?今 ...
- Vue3组合式API终极指南:从原理到实战,彻底掌握高效开发!
前言 在Vue3从发布到今天,组合式API已成为现代前端开发的标杆设计模式.本文通过真实项目场景,深度解析组合式API的核心特性,配以完整代码示例,助你彻底掌握企业级Vue应用开发精髓. 一.为什么组 ...
- windows goland go exec "gcc": executable file not found in %PATH%
问题 windows 本地缺少 gcc 编译器 解决方案 下载安装使用 MinGW-w64 第一种 https://winlibs.com/#download-release 下载后解压到磁盘中,然后 ...
- Centos下安装php mysql pdo以及gd扩展
pdo扩展安装: yum install php-pdo pdomysql扩展安装: yum install php-pdo_mysql gd库扩展安装: yum install php-gd 安装后 ...
- 怎么给EXE文件加启动参数
第一步 首先右键单击 exe 文件文件,创建 exe 文件的快捷方式. 第二步 右键单击此快捷方式--属性. 在快捷方式属性界面,点击目标后面的链接. 先打一个空格然后输入参数,然后点击应用按钮.确定 ...
- 实验二:D3数据可视化基础
实验目的: 熟悉 D3 数据可视化的使用方法. 实验原理: D3 的全称是(Data-Driven Documents),是一个被数据驱动的文档,其实就是 一个 JavaScript 的函数库,使用它 ...
- 【Python】使用PyInstaller把代码打包成exe可执行文件
使用PyInstaller打包自己写好的代码 零.需求 最近接到一个小单,需要批量修改文档内容,用Python做好后要打包成exe程序给客户的Win7电脑使用,此时需要用到PyInstaller打包自 ...
- 【虚拟机】VirualBox安装macOS系统
[虚拟机]VirualBox安装macOS系统 零.创建虚拟机 类型选择 Mac OS X 版本选择 macOS 10.13 High Sierra (64-bit) 注意:这边我设置的名称为 Mac ...
- 《机器人SLAM导航核心技术与实战》先导课:课程大纲
<机器人SLAM导航核心技术与实战>先导课:课程大纲 视频讲解 [先导课]1.课程大纲-视频讲解 [先导课]1.1.课程大纲-学习思维导图(上)-视频讲解 [先导课]1.2.课程大纲-学习 ...