前言

  我们在学习线程池的时候,都知道线程池的核心线程数、最大线程数、线程工厂等核心参数非常重要,故熟记于心。但是有些工作五六年的攻城狮可能说不出来怎么初始化一个全局线程池,以在不同场景使用;所以,本文基于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注解的时候,有以下几点需要注意,

  1. 返回值:若不需要返回值,则直接设置方法返回值为void;若需要,则返回值用AsyncResult或者CompletableFuture承接。
  2. 自定义执行器,例如:@Async("theGivenExecutor")。
  3. 如何开启异步:@Async注解必须在不同类间调用,如 A类—>B类.methodC()(@Async添加在B类的方法methodC上)。若在同一个类中进行方法嵌套调用,会变同步执行,例如:A类.methodB()—>A类.@Async methodC()。
  4. @Async加到类上,表示这个类的所有方法都是异步执行,并且方法上的注解会覆盖类上的注解。慎用此种使用注解的方式!

  老铁们, 因个人能力有限,难免有瑕疵,如果发现bug或者有更好的建议,那么请在文章下方留言!

Reference

https://www.jianshu.com/p/832f2b162450

Spring Boot注解之@Async和自定义线程池的更多相关文章

  1. 使用@Async注解创建多线程,自定义线程池

    说明 使用@Async注解创建多线程非常的方便,还可以通过配置,实现线程池.比直接使用线程池简单太多.而且在使用上跟普通方法没什么区别,加上个@Async注解即可实现异步调用. 用法 AsyncTas ...

  2. 【快学springboot】10.使用@Async注解创建多线程,自定义线程池

    说明 使用@Async注解创建多线程非常的方便,还可以通过配置,实现线程池.比直接使用线程池简单太多.而且在使用上跟普通方法没什么区别,加上个@Async注解即可实现异步调用. 用法 AsyncTas ...

  3. 多线程使用@Async注解创建多线程,自定义线程池

    转载自博客https://www.jianshu.com/p/7ac04a501eba

  4. Spring Boot中使用@Async的时候,千万别忘了线程池的配置!

    上一篇我们介绍了如何使用@Async注解来创建异步任务,我可以用这种方法来实现一些并发操作,以加速任务的执行效率.但是,如果只是如前文那样直接简单的创建来使用,可能还是会碰到一些问题.存在有什么问题呢 ...

  5. spring boot / cloud (四) 自定义线程池以及异步处理@Async

    spring boot / cloud (四) 自定义线程池以及异步处理@Async 前言 什么是线程池? 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线 ...

  6. Spring Boot使用@Async实现异步调用:自定义线程池

    前面的章节中,我们介绍了使用@Async注解来实现异步调用,但是,对于这些异步执行的控制是我们保障自身应用健康的基本技能.本文我们就来学习一下,如果通过自定义线程池的方式来控制异步调用的并发. 定义线 ...

  7. spring boot自定义线程池以及异步处理

    spring boot自定义线程池以及异步处理@Async:什么是线程池?线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使 ...

  8. SpringCloud 微服务中 @Async 注解自定义线程池 引发的aop 问题

    背景 在 使用springCloud 的@Async注解来做异步操作时,想自定义其线程池. 引发问题 自定义完线程池后,发现代码里并没有使用自定义线程池里的线程,于是新建一个demo工程,一样的配置代 ...

  9. Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

    多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程. 一.ThreadPoolTaskExecutor ...

  10. Spring Boot 2.X(十):自定义注册 Servlet、Filter、Listener

    前言 在 Spring Boot 中已经移除了 web.xml 文件,如果需要注册添加 Servlet.Filter.Listener 为 Spring Bean,在 Spring Boot 中有两种 ...

随机推荐

  1. C++中线程同步与互斥的四种方式介绍及对比详解

    引言 在C++中,当两个或更多的线程需要访问共享数据时,就会出现线程安全问题.这是因为,如果没有适当的同步机制,一个线程可能在另一个线程还没有完成对数据的修改就开始访问数据,这将导致数据的不一致性和程 ...

  2. 【Python脚本】路径管理之pathlib

    在Python的pathlib模块中,Path类和PurePath类是用于处理文件和目录路径的两个主要类.它们具有不同的目的和功能,以下是它们的主要异同点: 类的继承关系: Path类继承自PureP ...

  3. Pycharm pull 报错“Pull Failed: refusing to merge unrelated histories”

    分析: 在github已将建立仓库 pycharm clone到本地 pycharm pull 在第3步报错 "Pull Failed: refusing to merge unrelate ...

  4. 自动化-Yaml文件写入函数封装

    1.文件布局 打开文件修改读取方式为w dump函数写入文件 写入中文 使用allow_unicode=True class ReadConfiYaml: def __init__(self,yaml ...

  5. python 如何生成exe程序

    cmd 安装包 pip install pyinstaller cd 进入程序文件夹内 3.输入命令pyinstaller -F xx.py 在dist文件夹下找到安装包即可

  6. 什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

    说明 该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发). 该系统文章,我会尽量说的非常详细,做到不管新手.老手都能看懂. 说明:OverallAuth2 ...

  7. 选择排序(LOW)

    博客地址:https://www.cnblogs.com/zylyehuo/ # _*_coding:utf-8_*_ def select_sort(li): for i in range(len( ...

  8. 裸金属架构之服务器安装VMWare ESXI虚拟化平台详细流程

    目录1. 裸金属架构(Vcent)2. Vcent安装流程2.1 远程控制端(个人电脑)安装VMware-viclien2.2 服务器部署安装VMWare ESXI2.3 VMware-viclien ...

  9. Delphi 数据库连接查询分析器

    为了方便自己查询数据库信息,花了小时间写了小工具,添加SQL语法高亮显示功能

  10. 史上最全EffectiveJava总结(一)

    创建和销毁对象 1.静态工厂方法代替构造器 优点 静态工厂方法有名称,能确切地描述正被返回的对象. 不必每次调用都创建一个新的对象. 可以返回原返回类型的任何子类对象. 创建参数化类型实例时更加简洁, ...