最近在做订单模块,用户购买服务类产品之后,需要进行预约,预约成功之后分别给商家和用户发送提醒短信。考虑发短信耗时的情况所以我想用异步的方法去执行,于是就在网上看见了Spring的@Async了。

但是遇到了许多问题,使得@Async无效,也一直没有找到很好的文章去详细的说明@Async的正确及错误的使用方法及需要注意的地方,这里简单整理了一下遇见的问题,Sring是以配置文件的形式来开启@Async,而SpringBoot则是以注解的方式开启。

我们可以使用springBoot默认的线程池,不过一般我们会自定义线程池(因为比较灵活),配置方式有:

  1. 使用 xml 文件配置的方式
  2. 使用Java代码结合@Configuration进行配置(推荐使用)

下面分别实现两种配置方式

第一步、配置@Async

一、springBoot启动类的配置:

在Spring Boot的主程序中配置@EnableAsync,如下所示:

二、Spring XML的配置方式:

1.applicationContext.xml同目录下创建文件threadPool.xml文件:

2.然后在applicationContext.xml中引入threadPool.xml:<import resource="threadPool.xml" />

第二步:创建两个异步方法的类,如下所示:

第一个类(这里模拟取消订单后发短信,有两个发送短信的方法):

第二个类。调用发短信的方法 (异步方法不能与被调用的异步方法在同一个类中,否则无效):

经过测试得到如下结果:

1.没有使用@Async

2.使用了@Async

可以看出,没有使用@Async方式实现的发送短信是同步执行的,意思就是说第一条发送之后再发送第二条,第二条发送成功之后再给用户提示,这样显然会影响用户体验,再看使用了@Async实现的,在执行第一个发送短信方法之后马上开启另一个线程执行第二个方法,显然这样我们的处理速度回快很多。

使用Java代码结合@Configuration注解的配置方式(推荐使用)

1. 新建一个配置类

package com.boot.common.conf;

import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.scheduling.annotation.EnableAsync;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**

* 线程池配置

*@authorzhh

*

*/

@Configuration

@EnableAsync

public classThreadPoolTaskConfig{

/**

* 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,

* 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

* 当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝

*/

/** 核心线程数(默认线程数) */

private static final int corePoolSize = 20;

/** 最大线程数 */

private static final int maxPoolSize = 100;

/** 允许线程空闲时间(单位:默认为秒) */

private static final int keepAliveTime = 10;

/** 缓冲队列大小 */

private static final int queueCapacity = 200;

/** 线程池名前缀 */

private static final String threadNamePrefix = "Async-Service-";

@Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名

publicThreadPoolTaskExecutortaskExecutor(){

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

executor.setCorePoolSize(corePoolSize);

executor.setMaxPoolSize(maxPoolSize);

executor.setQueueCapacity(queueCapacity);

executor.setKeepAliveSeconds(keepAliveTime);

executor.setThreadNamePrefix(threadNamePrefix);

// 线程池对拒绝任务的处理策略

// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

// 初始化

executor.initialize();

return executor;

}

}

2.创建两个异步方法的类(和之前的类类似仅仅是方法上注解不一样),如下所示:

第一个类(这里模拟取消订单后发短信,有两个发送短信的方法):

代码中的 @Async("taskExecutor") 对应我们自定义线程池中的 @Bean("taskExecutor") ,表示使用我们自定义的线程池。

第二个类。调用发短信的方法 (异步方法不能与被调用的异步方法在同一个类中,否则无效):

运行截图:

注意看,截图中的 [nio-8090-exec-1] 是Tomcat的线程名称

[Async-Service-1]、[Async-Service-2]表示线程1和线程2 ,是我们自定义的线程池里面的线程名称,我们在配置类里面定义的线程池前缀:

private static final String threadNamePrefix = "Async-Service-"; // 线程池名前缀,说明我们自定义的线程池被使用了。

注意事项

如下方式会使@Async失效

  • 异步方法使用static修饰
  • 异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
  • 异步方法不能与被调用的异步方法在同一个类中
  • 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
  • 如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解

SpringBoot线程池的创建、@Async配置步骤及注意事项的更多相关文章

  1. Spring及SpringBoot @Async配置步骤及注意事项

    前言 最近在做一个用户反馈的功能,就是当用户反馈意见或建议后服务端将意见保存然后发邮件给相关模块的开发者.考虑发邮件耗时的情况所以我想用异步的方法去执行,于是就开始研究Spring的@Async了.但 ...

  2. springboot线程池@Async的使用和扩展

    我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,今天我们就来实战体验这个线程池服务: 本 ...

  3. springboot 线程池

    我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,今天我们就来实战体验这个线程池服务: 本 ...

  4. springboot线程池的使用和扩展(转)

    springboot线程池的使用和扩展 我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行, ...

  5. springboot线程池的使用和扩展

    我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,今天我们就来实战体验这个线程池服务: 本 ...

  6. [开源项目]可观测、易使用的SpringBoot线程池

    在开发spring boot应用服务的时候,难免会使用到异步任务及线程池.spring boot的线程池是可以自定义的,所以我们经常会在项目里面看到类似于下面这样的代码 @Bean public Ex ...

  7. 并发编程 13—— 线程池的使用 之 配置ThreadPoolExecutor 和 饱和策略

    Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...

  8. Linux下通用线程池的创建与使用

    线程池:简单地说,线程池 就是预先创建好一批线程,方便.快速地处理收到的业务.比起传统的到来一个任务,即时创建一个线程来处理,节省了线程的创建和回收的开销,响应更快,效率更高. 在linux中,使用的 ...

  9. Java线程池的创建详解

    本篇文章主要总结了Java创建线程池的三种方式以及线程池参数的详细说明,对线程池感兴趣的同学可以作为参考学习. 1)通过工具类java.util.concurrent.Executors的静态方法来创 ...

随机推荐

  1. vscode 将本地项目上传到github、从github克隆项目以及删除github上的某个文件夹

    一.将本地项目上传到github 1.创建本地仓库(文件夹) mkdir study//创建文件夹studycd study //进入study文件夹 2.通过命令git init把这个文件夹变成Gi ...

  2. 最优运输(Optimal Transfort):从理论到填补的应用

    目录 引言 1 背景 2 什么是最优运输? 3 基本概念 3.1 离散测度 (Discrete measures) 3.2 蒙日(Monge)问题 3.3 Kantorovich Relaxation ...

  3. 马哥Linux SysAdmin学习笔记(四)

    sed:编辑器 sed:Stream EDitor,行编辑器 用法: sed [option]... 'script' inputfile... script: '地址命令' 常用选项: -n:不输出 ...

  4. 单用户模式修改root密码

    单用户模式修改root密码 1.进入引导菜单界面2.按e进入grub,在linux或linux16那行结尾加上 rw init=/bin/bash,按Ctrl+x或F103.进入bash-4.3# , ...

  5. 怎样使用yum-cron为CentOS7自动更新重要的安全补丁

    怎样使用yum-cron为CentOS自动更新重要的安全补丁 2017年4月19日 | 分类: [技术] 参考:https://linux.die.net/man/8/yum-cron参考:http: ...

  6. qt利用QT designer构建第一个界面helloworld工程

    qt利用QT designer构建第一个界面helloworld工程原创ZJE_ANDY 发布于2017-04-07 20:25:28 阅读数 6613 收藏展开第一步:点击New Project 第 ...

  7. 10.1 ifconfig:配置或显示网络接口信息

    ifconfig命令 用于配置网卡IP地址等网络参数或显示当前网络的接口状态,其类似于Windows下的ipconfig命令,这两个命令很容易混淆,读者需要区分一下.此外,ifconfig命令在配置网 ...

  8. Java反射机制 之 获取类的 方法 和 属性(包括构造函数)(Day_06)

    把自己立成帆,才能招来凤. 运行环境 JDK8 + IntelliJ IDEA 2018.3  本文中使用的jar包链接 https://files.cnblogs.com/files/papercy ...

  9. SpringBoot2 集成测试组件,七种测试手段对比

    一.背景描述 在版本开发中,时间段大致的划分为:需求,开发,测试: 需求阶段:理解需求做好接口设计: 开发阶段:完成功能开发和对接: 测试上线:自测,提测,修复,上线: 实际上开发阶段两个核心的工作, ...

  10. C 语言通用模板队列

    前言 嵌入式开发过程中,各个模块之间,各个设备之间进行交互时,都会存在数据的输入输出,由于处理的方式不同,数据不会立即同步处理,因此通常在设计时都会设计缓冲区进行数据的处理,方式数据丢失等问题:一个项 ...