免费在线a视频-免费在线观看a视频-免费在线观看大片影视大全-免费在线观看的视频-色播丁香-色播基地

SpringBoot線程池的創(chuàng)建、@Async配置步驟及注意事項

:2020年02月21日 腳本之家
分享到:

最近在做訂單模塊,用戶購買服務(wù)類產(chǎn)品之后,需要進(jìn)行預(yù)約,預(yù)約成功之后分別給商家和用戶發(fā)送提醒短信。考慮發(fā)短信耗時的情況所以我想用異步的方法去執(zhí)行,于是就在網(wǎng)上看見了Spring的@Async了。但是遇...

最近在做訂單模塊,用戶購買服務(wù)類產(chǎn)品之后,需要進(jìn)行預(yù)約,預(yù)約成功之后分別給商家和用戶發(fā)送提醒短信。考慮發(fā)短信耗時的情況所以我想用異步的方法去執(zhí)行,于是就在網(wǎng)上看見了Spring的@Async了。

但是遇到了許多問題,使得@Async無效,也一直沒有找到很好的文章去詳細(xì)的說明@Async的正確及錯誤的使用方法及需要注意的地方,這里簡單整理了一下遇見的問題,Sring是以配置文件的形式來開啟@Async,而SpringBoot則是以注解的方式開啟。

我們可以使用springBoot默認(rèn)的線程池,不過一般我們會自定義線程池(因為比較靈活),配置方式有:

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

  2. 使用Java代碼結(jié)合@Configuration進(jìn)行配置(推薦使用)

下面分別實現(xiàn)兩種配置方式

第一步、配置@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同目錄下創(chuàng)建文件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">

        <!-- 核心線程數(shù),默認(rèn)為1 -->

        <property name="corePoolSize" value="10" />

        <!-- 最大線程數(shù),默認(rèn)為Integer.MAX_VALUE -->

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

        <!-- 隊列最大長度,一般需要設(shè)置值>=notifyScheduledMainExecutor.maxNum;默認(rèn)為Integer.MAX_VALUE -->

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

        <!-- 線程池維護(hù)線程所允許的空閑時間,默認(rèn)為60s -->

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

        <!-- 完成任務(wù)自動關(guān)閉 , 默認(rèn)為false-->

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

        <!-- 核心線程超時退出,默認(rèn)為false -->

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

        <!-- 線程池對拒絕任務(wù)(無線程可用)的處理策略,目前只支持AbortPolicy、CallerRunsPolicy;默認(rèn)為后者 -->

        <property name="rejectedExecutionHandler">

            <!-- AbortPolicy:直接拋出java.util.concurrent.RejectedExecutionException異常 -->

            <!-- CallerRunsPolicy:主線程直接執(zhí)行該任務(wù),執(zhí)行完之后嘗試添加下一個任務(wù)到線程池中,可以有效降低向線程池內(nèi)添加任務(wù)的速度 -->

            <!-- DiscardOldestPolicy:拋棄舊的任務(wù)、暫不支持;會導(dǎo)致被丟棄的任務(wù)無法再次被執(zhí)行 -->

            <!-- DiscardPolicy:拋棄當(dāng)前任務(wù)、暫不支持;會導(dǎo)致被丟棄的任務(wù)無法再次被執(zhí)行 -->

            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />

        </property>

    </bean>

</beans>

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

<!--如果不使用自定義線程池,可以直接使用下面這段標(biāo)簽-->

<!-- 

<task:executor id="WhifExecutor" pool-size="10"/> 

-->

<import resource="threadPool.xml" />

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

第二步:創(chuàng)建兩個異步方法的類,如下所示:

第一個類(這里模擬取消訂單后發(fā)短信,有兩個發(fā)送短信的方法):

@Service

public class TranTest2Service {

    // 發(fā)送提醒短信 1

    @Async

    public void sendMessage1() throws InterruptedException {

        System.out.println("發(fā)送短信方法---- 1   執(zhí)行開始");

        Thread.sleep(5000); // 模擬耗時

        System.out.println("發(fā)送短信方法---- 1   執(zhí)行結(jié)束");

    }

    // 發(fā)送提醒短信 2

    @Async

    public void sendMessage2() throws InterruptedException {

        System.out.println("發(fā)送短信方法---- 2   執(zhí)行開始");

        Thread.sleep(2000); // 模擬耗時

        System.out.println("發(fā)送短信方法---- 2   執(zhí)行結(jié)束");

    }

}

第二個類。調(diào)用發(fā)短信的方法 (異步方法不能與被調(diào)用的異步方法在同一個類中,否則無效):

@Service

public class OrderTaskServic {

    @Autowired

    private TranTest2Service tranTest2Service;

    // 訂單處理任務(wù)

    public void orderTask() throws InterruptedException {

        this.cancelOrder(); // 取消訂單

        tranTest2Service.sendMessage1(); // 發(fā)短信的方法   1

        tranTest2Service.sendMessage2(); // 發(fā)短信的方法  2

    }

    // 取消訂單

    public void cancelOrder() throws InterruptedException {

        System.out.println("取消訂單的方法執(zhí)行------開始");

        System.out.println("取消訂單的方法執(zhí)行------結(jié)束 ");

    }

}

經(jīng)過測試得到如下結(jié)果:

1.沒有使用@Async

2.使用了@Async

可以看出,沒有使用@Async方式實現(xiàn)的發(fā)送短信是同步執(zhí)行的,意思就是說第一條發(fā)送之后再發(fā)送第二條,第二條發(fā)送成功之后再給用戶提示,這樣顯然會影響用戶體驗,再看使用了@Async實現(xiàn)的,在執(zhí)行第一個發(fā)送短信方法之后馬上開啟另一個線程執(zhí)行第二個方法,顯然這樣我們的處理速度回快很多。

使用Java代碼結(jié)合@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 {

/** 

 *   默認(rèn)情況下,在創(chuàng)建了線程池后,線程池中的線程數(shù)為0,當(dāng)有任務(wù)來之后,就會創(chuàng)建一個線程去執(zhí)行任務(wù),

 *    當(dāng)線程池中的線程數(shù)目達(dá)到corePoolSize后,就會把到達(dá)的任務(wù)放到緩存隊列當(dāng)中;

 *  當(dāng)隊列滿了,就繼續(xù)創(chuàng)建線程,當(dāng)線程數(shù)量大于等于maxPoolSize后,開始使用拒絕策略拒絕 

 */

    /** 核心線程數(shù)(默認(rèn)線程數(shù)) */

    private static final int corePoolSize = 20;

    /** 最大線程數(shù) */

    private static final int maxPoolSize = 100;

    /** 允許線程空閑時間(單位:默認(rèn)為秒) */

    private static final int keepAliveTime = 10;

    /** 緩沖隊列大小 */

    private static final int queueCapacity = 200;

    /** 線程池名前綴 */

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

    @Bean("taskExecutor") // bean的名稱,默認(rèn)為首字母小寫的方法名

    public ThreadPoolTaskExecutor taskExecutor(){

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setCorePoolSize(corePoolSize);   

        executor.setMaxPoolSize(maxPoolSize);

        executor.setQueueCapacity(queueCapacity);

        executor.setKeepAliveSeconds(keepAliveTime);

        executor.setThreadNamePrefix(threadNamePrefix);

        // 線程池對拒絕任務(wù)的處理策略

        // CallerRunsPolicy:由調(diào)用線程(提交任務(wù)的線程)處理該任務(wù)

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

        // 初始化

        executor.initialize();

        return executor;

    }

}

2.創(chuàng)建兩個異步方法的類(和之前的類類似僅僅是方法上注解不一樣),如下所示:

第一個類(這里模擬取消訂單后發(fā)短信,有兩個發(fā)送短信的方法):

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);

    // 發(fā)送提醒短信 1

        @PostConstruct // 加上該注解項目啟動時就執(zhí)行一次該方法

    @Async("taskExecutor")

    public void sendMessage1() throws InterruptedException {

        log.info("發(fā)送短信方法---- 1   執(zhí)行開始");

        Thread.sleep(5000); // 模擬耗時

        log.info("發(fā)送短信方法---- 1   執(zhí)行結(jié)束");

    }

    // 發(fā)送提醒短信 2

        @PostConstruct // 加上該注解項目啟動時就執(zhí)行一次該方法

    @Async("taskExecutor")

    public void sendMessage2() throws InterruptedException {

        log.info("發(fā)送短信方法---- 2   執(zhí)行開始");

        Thread.sleep(2000); // 模擬耗時

        log.info("發(fā)送短信方法---- 2   執(zhí)行結(jié)束");

    }

}

代碼中的 @Async("taskExecutor") 對應(yīng)我們自定義線程池中的 @Bean("taskExecutor") ,表示使用我們自定義的線程池。

第二個類。調(diào)用發(fā)短信的方法 (異步方法不能與被調(diào)用的異步方法在同一個類中,否則無效):

@Service

public class OrderTaskServic {

    @Autowired

    private TranTest2Service tranTest2Service;

    // 訂單處理任務(wù)

    public void orderTask() throws InterruptedException {

        this.cancelOrder(); // 取消訂單

        tranTest2Service.sendMessage1(); // 發(fā)短信的方法   1

        tranTest2Service.sendMessage2(); // 發(fā)短信的方法  2

    }

    // 取消訂單

    public void cancelOrder() throws InterruptedException {

        System.out.println("取消訂單的方法執(zhí)行------開始");

        System.out.println("取消訂單的方法執(zhí)行------結(jié)束 ");

    }

}

運行截圖:

注意看,截圖中的 [nio-8090-exec-1] 是Tomcat的線程名稱

[Async-Service-1]、[Async-Service-2]表示線程1和線程2 ,是我們自定義的線程池里面的線程名稱,我們在配置類里面定義的線程池前綴:

private static final String threadNamePrefix = "Async-Service-"; // 線程池名前綴,說明我們自定義的線程池被使用了。

注意事項

如下方式會使@Async失效

  • 異步方法使用static修飾

  • 異步類沒有使用@Component注解(或其他注解)導(dǎo)致spring無法掃描到異步類

  • 異步方法不能與被調(diào)用的異步方法在同一個類中

  • 類中需要使用@Autowired或@Resource等注解自動注入,不能自己手動new對象

  • 如果使用SpringBoot框架必須在啟動類中增加@EnableAsync注解

[我要糾錯]
[編輯:王振袢 &發(fā)表于江蘇]
關(guān)鍵詞: 最近 在做 訂單 模塊 用戶

來源:本文內(nèi)容搜集或轉(zhuǎn)自各大網(wǎng)絡(luò)平臺,并已注明來源、出處,如果轉(zhuǎn)載侵犯您的版權(quán)或非授權(quán)發(fā)布,請聯(lián)系小編,我們會及時審核處理。
聲明:江蘇教育黃頁對文中觀點保持中立,對所包含內(nèi)容的準(zhǔn)確性、可靠性或者完整性不提供任何明示或暗示的保證,不對文章觀點負(fù)責(zé),僅作分享之用,文章版權(quán)及插圖屬于原作者。

點個贊
0
踩一腳
0

您在閱讀:SpringBoot線程池的創(chuàng)建、@Async配置步驟及注意事項

Copyright©2013-2025 ?JSedu114 All Rights Reserved. 江蘇教育信息綜合發(fā)布查詢平臺保留所有權(quán)利

蘇公網(wǎng)安備32010402000125 蘇ICP備14051488號-3技術(shù)支持:南京博盛藍(lán)睿網(wǎng)絡(luò)科技有限公司

南京思必達(dá)教育科技有限公司版權(quán)所有   百度統(tǒng)計

主站蜘蛛池模板: 在线国产一区二区 | 久色网站 | 野外一级毛片 | 国产精品一区二区在线观看 | 天堂v亚洲国产v一区二区 | 国产精品久久久久久久久免费hd | 丝袜久久 | 天天射综合 | 亚洲中午字幕 | 欧美在线视频免费 | 久久91精品久久久久久水蜜桃 | 天天躁夜夜躁狠狠躁2021a | 性色a v 一区 | 波多野吉衣在线多野结衣 | 国产一级片免费视频 | 亚洲最新中文字幕 | 2019天天干天天操 | 成年人免费在线看 | 在线观看毛片视频 | 波多野结衣一区二区三区四区 | 欧美日韩国产一区二区三区不卡 | 亚洲丶国产丶欧美一区二区三区 | 污视频网站免费 | 操日韩| 北条麻妃国产九九九精品视频 | 亚洲图片自拍偷拍 | 日韩a一级欧美一级在线播放 | 六月丁香啪啪六月激情 | 亚洲成a人片在线观看88 | 天天干天天操天天爽 | 国产一级在线播放 | 97免费在线观看视频 | 伦理片中文 | 日本一区二区三区中文字幕 | 午夜免费福利 | 久操视频免费在线观看 | 亚洲影院在线播放 | 黄色小视频免费 | 欧美久在线观看在线观看 | 最近最新免费中文字幕高清 | 成人毛片视频免费网站观看 |
最熱文章
最新文章
  • 阿里云上云鉅惠,云產(chǎn)品享最低成本,有需要聯(lián)系,
  • 卡爾蔡司鏡片優(yōu)惠店,鏡片價格低
  • 蘋果原裝手機(jī)殼