@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.pswp.cn/news/534954.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/534954.shtml
英文地址,請注明出處:http://en.pswp.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…

MySQL摘要_mysql摘要

2011-04-15(1)mysqld關閉命令&#xff1a;mysqladmin -u root shutdown。注意&#xff1a;windows命令以enter結束不是;&#xff0c;mysql命令行才是(2)mysql終端接入&#xff0c;修改mysql.user表內容&#xff0c;添加授權用戶。insert into mysql.user(Host,User,Password,ss…

錯誤代碼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;命…

java mysql dump_Java 調用Mysql dump 備份數據庫

SimpleDateFormat sdf new SimpleDateFormat("yyyyMMddHHmmss");try {String name sdf.format(new Date());String filePath System.getProperty("user.dir") "//" name ".sql";// 系統執行器Runtime rt Runtime.getRuntime();…

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:{ # 輸…

mysql事務隔離最高_Mysql事務隔離級別

mysql官方文檔顯示&#xff1a;InnoDB中每個隔離級別的詳細描述如下&#xff1a; READ UNCOMMITTEDSELECT語句以非鎖定方式被執行&#xff0c;但是一個可能更早期版本的記錄會被用到。因此&#xff0c;使用這個隔離級別&#xff0c;比如&#xff0c;讀是不連貫的。著也被稱為“…

exe打包工具哪個最好_一鍵分發工具哪個最好用?這款30萬人都在用,很優秀!...

現代化媒體對于傳播越來越重要&#xff0c;16年到如今&#xff0c;視頻內容產業實在有話題度&#xff0c;其高效的粉絲互動機制、低資金投入高額回報等等亮點&#xff0c;強烈吸引著數以百萬計的創造者&#xff0c;為了達到極其出色的閱讀量&#xff0c;這些人往往會運用到所有…

mysql備份服務器中的_使用 Shell 備份遠程服務器上的 MySQL 數據庫到本機

適用場景&#xff1a;遠程服務器上的 MySQL 不允許遠程訪問&#xff0c;此時我們需要先登錄服務器&#xff0c;備份數據庫后&#xff0c;將備份文件拉取到本機。源碼 mysqlDumpRemote2Local.sh#!/bin/bash################################################# TODO: 登錄遠程服務…

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物理文…