@async 默认线程池_SpringBoot 线程池的使用

dd62c525e239f59ee1860ab2e0e0a965.png  Java大联盟

  帮助万千Java学习者持续成长

关注

b9b099c3e635b70667455caf99955906.gif

作者|Muscleheng

blog.csdn.net/Muscleheng/article/details/81409672

前言

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

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

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

  1. 使用 xml 文件配置的方式

  2. 使用Java代码结合@Configuration进行配置(推荐使用)

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

第一步、配置@Async

一、springBoot启动类的配置:

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

@ServletComponentScan
@SpringBootApplication
@EnableAsync
public class ClubApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(ClubApiApplication.class, args);
    }
}

二、Spring XML的配置方式:

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

<?xml  version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">

    
    <task:annotation-driven executor="threadPool" />

    
    <bean id="threadPool"class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        
        <property name="corePoolSize" value="10" />

        
        <property name="maxPoolSize" value="50" />

        
        <property name="queueCapacity" value="100" />

        
        <property name="keepAliveSeconds" value="30" />

        
        <property name="waitForTasksToCompleteOnShutdown" value="true" />

        
        <property name="allowCoreThreadTimeOut" value="true" />

        
        <property name="rejectedExecutionHandler">
            
            
            
            
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
        property>
    bean>
beans>

2.然后在applicationContext.xml中引入threadPool.xml:



<import resource="threadPool.xml" />
<task:annotation-driven executor="WhifExecutor" />

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

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

@Service
public class TranTest2Service {


    // 发送提醒短信 1
    @Async
    public void sendMessage1() throws InterruptedException {

        System.out.println("发送短信方法---- 1   执行开始");
        Thread.sleep(5000); // 模拟耗时
        System.out.println("发送短信方法---- 1   执行结束");
    }

    // 发送提醒短信 2
    @Async
    public void sendMessage2() throws InterruptedException {

        System.out.println("发送短信方法---- 2   执行开始");
        Thread.sleep(2000); // 模拟耗时
        System.out.println("发送短信方法---- 2   执行结束");
    }
}

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

@Service
public class OrderTaskServic {
    @Autowired
    private TranTest2Service tranTest2Service;

    // 订单处理任务
    public void orderTask() throws InterruptedException {

        this.cancelOrder(); // 取消订单
        tranTest2Service.sendMessage1(); // 发短信的方法   1
        tranTest2Service.sendMessage2(); // 发短信的方法  2

    }

    // 取消订单
    public void cancelOrder() throws InterruptedException {
        System.out.println("取消订单的方法执行------开始");
        System.out.println("取消订单的方法执行------结束 ");
    }

}

经过测试得到如下结果:

1.没有使用@Async

942cda5c631b15792ca3368bb21497ba.png

2.使用了@Async

f3857f353709a3abc833c3222f668f0b.png

可以看出,没有使用@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;

/**
 * 线程池配置
 * @author zhh
 *
 */
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {

/** 
 *   默认情况下,在创建了线程池后,线程池中的线程数为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的名称,默认为首字母小写的方法名
    public ThreadPoolTaskExecutor taskExecutor(){
        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.创建两个异步方法的类(和之前的类类似仅仅是方法上注解不一样),如下所示:

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

package com.boot.test1.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class TranTest2Service {
    Logger log = LoggerFactory.getLogger(TranTest2Service.class);

    // 发送提醒短信 1
        @PostConstruct // 加上该注解项目启动时就执行一次该方法
    @Async("taskExecutor")
    public void sendMessage1() throws InterruptedException {
        log.info("发送短信方法---- 1   执行开始");
        Thread.sleep(5000); // 模拟耗时
        log.info("发送短信方法---- 1   执行结束");
    }

    // 发送提醒短信 2
        @PostConstruct // 加上该注解项目启动时就执行一次该方法
    @Async("taskExecutor")
    public void sendMessage2() throws InterruptedException {

        log.info("发送短信方法---- 2   执行开始");
        Thread.sleep(2000); // 模拟耗时
        log.info("发送短信方法---- 2   执行结束");
    }
}

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

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

@Service
public class OrderTaskServic {
    @Autowired
    private TranTest2Service tranTest2Service;

    // 订单处理任务
    public void orderTask() throws InterruptedException {

        this.cancelOrder(); // 取消订单
        tranTest2Service.sendMessage1(); // 发短信的方法   1
        tranTest2Service.sendMessage2(); // 发短信的方法  2

    }

    // 取消订单
    public void cancelOrder() throws InterruptedException {
        System.out.println("取消订单的方法执行------开始");
        System.out.println("取消订单的方法执行------结束 ");
    }

}

运行截图:

27554a139bd2b3544e0f3899295722b7.png

注意看,截图中的 [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注解

推荐阅读

1、B站原创,2020版前后端分离视频教程

2、Spring Boot源码解析

3、一文搞懂前后端分离

4、快速上手Spring Boot+Vue前后端分离

楠哥简介

资深 Java 工程师,微信号 nnsouthwind

《Java零基础实战》一书作者,今日头条认证大V

GitChat认证作者,B站认证UP主(楠哥教你学Java)

致力于帮助万千 Java 学习者持续成长。

ed25ddc071f98ed0e18f8d5aa5928b26.png

有收获,就在看4852f1d272c744c295123b28846fd40f.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/534954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 横向扩展 中间件_mysql-proxy数据库中间件架构 | 架构师之路

一、mysql-proxy简介mysql-proxy是mysql官方提供的mysql中间件服务&#xff0c;上游可接入若干个mysql-client&#xff0c;后端可连接若干个mysql-server。它使用mysql协议&#xff0c;任何使用mysql-client的上游无需修改任何代码&#xff0c;即可迁移至mysql-proxy上。mysql-…

python selenium对象怎么序列化_python selenium爬取斗鱼

不加延迟报错selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {“method”:”xpath”,”selector”:”.//span[class”DyListCover-hot”]”}(Session info: chrome80.0.3987.122)最开始以为是版本问题&#xff0c;不…

神经网络的全连接层_深度神经网络全连接层

一、概念全连接层一般在网络的最后部分做分类输出&#xff0c;全连接层的有m个输入和n个输出&#xff0c;每一个输出都和所有的输入相连&#xff0c;相连的权重w都是不一样的&#xff0c;同时每一个输出还有一个bias。二、前向全连接假设输入是4&#xff0c;输出是4&#xff0c…

vs 选定内容没有属性页_从智能单品,到全屋智能:2019中国智能家居发展白皮书【附82页PPT】...

2019年&#xff0c;智能家居行业在技术、市场和行业的变革中迎接新的挑战和机遇。一方面&#xff0c;AI、IoT、边缘计算全面赋能智能家居&#xff1b;另一方面&#xff0c;中国的房地产行业正在从上半场的“增量开发”&#xff0c;切换到下半场的“存量经营”、“楼盘精装化”政…

python决策树的应用_机器学习-决策树实战应用

1.下载2.安装&#xff1a;双击3.创建桌面快捷方式安装目录\bin文件夹\&#xff1a;找到gvedit.exe文件右键 发送到桌面快捷方式&#xff0c;如下图&#xff1a;4.配置环境变量将graphviz安装目录下的bin文件夹添加到Path环境变量中&#xff1a;5.验证是否安装并配置成功进入win…

【SSM面向CRUD编程专栏 3】关于黑马程序员最全SSM框架教程视频,P37集老师跳过的模块创建以及tomcat下载安装配置和运行等诸多问题

写在前面&#xff1a;​ 本人是在学习B站黑马程序员SSM框架教程视频的时候在P37集遇到了问题&#xff0c;如果不解决还没办法往下接着听&#xff0c;老师跳过的模块创建以及tomcat下载安装配置和运行等诸多问题&#xff0c;全在这篇博客中得到了解决 &#x1f622;解决上…

python人脸识别源码_Python 抖音机器人,让你找到漂亮小姐姐

本项目作者沉迷于抖音无法自拔&#xff0c;常常花好几个小时在抖音漂亮小姐姐身上。本着高效、直接地找到漂亮小姐姐的核心思想&#xff0c;我用 Python ADB 做了一个 Python 抖音机器人 Douyin-Bot。特性自动翻页颜值检测人脸识别自动点赞自动关注随机防 Ban自动评论原理打开…

thinkphp josn mysql_ThinkPHP:JSON字段类型的使用(ORM)

ThinkPHP5.1版本正式发布已经有一段时间了&#xff0c;我会陆续给大家介绍其中的新特性。今天要给大家介绍的是一个可能很多用户还不了解的一个特性&#xff1a;JSON字段数据支持。不过首先注意一点&#xff0c;本篇内容中描述的JSON字段数据的支持是从V5.1.4版本引入的。由于包…

获取http地址如何从上面抓取图片_用 Python 自动抓取妹子图

目录前言Media Pipeline启用Media Pipeline使用 ImgPipeline抓取妹子图瞎比比与送书后话前言我们在抓取数据的过程中&#xff0c;除了要抓取文本数据之外&#xff0c;当然也会有抓取图片的需求。那我们的 scrapy 能爬取图片吗&#xff1f;答案是&#xff0c;当然的。说来惭愧&a…

错误代码0x800f0950怎么解决_解决win10安装net framework 3.5失败(错误代码 0x800F0950)...

视频教程&#xff1a;Win10教程 安装net framework 3.5失败(错误代码 0x800F0950)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​www.bilibili.com一&#xff1a;出现问题&#xff1a;报错代码二&#xff1a;解决步骤1.通过命令提示符明确自己系统版本Windows键X ,打开&#xff08;命…

python 日志不会按照日期分割_django实现日志按日期分割

settings文件中配置&#xff1a; LOGGING { version:1, disable_existing_logger:False, formatters:{ verbose:{ format:%(asctime)s \"%(pathname)s&#xff1a;%(module)s:%(funcName)s:%(lineno)d\" [%(levelname)s]-%(message)s }, }, # 处理器 handlers:{ # 输…

exe打包工具哪个最好_一键分发工具哪个最好用?这款30万人都在用,很优秀!...

现代化媒体对于传播越来越重要&#xff0c;16年到如今&#xff0c;视频内容产业实在有话题度&#xff0c;其高效的粉丝互动机制、低资金投入高额回报等等亮点&#xff0c;强烈吸引着数以百万计的创造者&#xff0c;为了达到极其出色的阅读量&#xff0c;这些人往往会运用到所有…

date转timestamp格式_技术分享 | MySQL:timestamp 时区转换导致 CPU %sy 高的问题

作者&#xff1a;高鹏文章末尾有他著作的《深入理解 MySQL 主从原理 32 讲》&#xff0c;深入透彻理解 MySQL 主从&#xff0c;GTID 相关技术知识。本文为学习记录&#xff0c;可能有误请谅解。本文建议PC端观看&#xff0c;效果更佳。这个问题是一个朋友遇到的风云&#xff0c…

mysql架构组成_第 2 章 MySQL 架构组成

麻雀虽小&#xff0c;五脏俱全。MySQL 虽然以简单著称&#xff0c;但其内部结构并不简单。本章从MySQL物理组成、逻辑组成&#xff0c;以及相关工具几个角度来介绍 MySQL 的整体架构组成&#xff0c;希望能够让读者对 MySQL 有一个更全面深入的了解。2&#xff0e;1 MySQL物理文…

win2008 mysql端口_使用自定义端口连接SQL Server 2008的方法

使用过SQL Server的人大多都知道&#xff0c;SQL Server服务器默认监听的端口号是1433&#xff0c;但是我今天遇到的问题是我的机器上有三个数据库实例&#xff0c;这样使用TCP/IP远程连接时就产生了问题。如何在Microsoft SQL Server Management Studio里加入端口号连接呢&…

python基本命令range_Python的Range()函数(指南)

当需要执行特定次数的操作时&#xff0c;Python内置的range函数十分方便。 读罢本文&#xff0c;你将&#xff1a; 理解Python的range函数是如何工作的 了解Python 2和Python 3中的实现方式有何不同 看过了不少range()函数操作实例 有能力解决它的一些局限性 让我们开始吧&…

qos的_QoS 概述

QoS 是一个很大的领域&#xff0c;涉及到网络中的多个层次和环节。本文仅简要的谈谈 Endpoint 侧的 QoS 概念&#xff0c;将这些纷繁的概念名词串起来&#xff0c;便于理解。QoS 技术背景下图说明了 QoS workflow 中&#xff0c;各项技术的位置和关系摘自 &amp;lt; 端到端Q…

centos daemonize_手把手教你在centos上配置Django项目(超详细步骤)

前言关于Django的部署&#xff0c;本人也踩了很多坑&#xff0c;这篇文章一步一步教你怎么进行部署&#xff0c;只需要你按照我的步骤来就OK了&#xff01;这里我们使用的服务器是一个全新的服务器&#xff0c;没有安装任何东西。基础环境搭建步骤★ 注意&#xff1a;下面的步骤…

mysql8.0.17压缩包安装教程_mysql 8.0.16 压缩包安装配置方法图文教程

本文为大家分享了mysql 8.0.16 压缩包安装配置方法&#xff0c;供大家参考&#xff0c;具体内容如下运行环境&#xff1a;windows 10 x641、下载zip安装包&#xff1a;mysql8.0 for windows zip包&#xff1a;&#xff0c;进入页面后可以不用登录。后点击底部“no thanks, just…

Mysql保存是事件驱动吗_【CHRIS RICHARDSON 微服务系列】事件驱动的数据管理-5

编者的话 |本文来自 Nginx 官方博客&#xff0c;是「Chris Richardson 微服务」系列的第五篇文章。第一篇文章介绍了微服务架构模式&#xff0c;并且讨论了使用微服务的优缺点&#xff1b;第二和第三篇描述了微服务架构模块间通讯的不同方面&#xff1b;第四篇研究了服务发现中…