第07課:Spring Boot 異步框架

一、課程目標(biāo)

熟悉spring的異步框架找蜜,學(xué)會使用異步@Async注解

二饼暑、為什么要用異步框架,它解決什么問題洗做?

在SpringBoot的日常開發(fā)中弓叛,一般都是同步調(diào)用的。但經(jīng)常有特殊業(yè)務(wù)需要做異步來處理诚纸,例如:注冊新用戶撰筷,送100個積分,或下單成功畦徘,發(fā)送push消息等等毕籽。
就拿注冊新用戶為什么要異步處理?

  • 第一個原因:容錯性井辆,如果送積分出現(xiàn)異常关筒,不能因為送積分而導(dǎo)致用戶注冊失敗杯缺;
    因為用戶注冊是主要功能蒸播,送積分是次要功能,即使送積分異常也要提示用戶注冊成功萍肆,然后后面在針對積分異常做補償處理袍榆。
  • 第二個原因:提升性能,例如注冊用戶花了20毫秒塘揣,送積分花費50毫秒包雀,如果用同步的話,總耗時70毫秒亲铡,用異步的話才写,無需等待積分,故耗時20毫秒奖蔓。
    故琅摩,異步能解決2個問題,性能和容錯性锭硼。

三、SpringBoot異步調(diào)用

在SpringBoot中使用異步調(diào)用是很簡單的蜕劝,只需要使用@Async注解即可實現(xiàn)方法的異步調(diào)用檀头。

四轰异、@Async異步調(diào)用例子

步驟1:開啟異步任務(wù)

采用@EnableAsync來啟用異步任務(wù)支持,另外需要用@Configuration來把當(dāng)前類加入springIOC容器中

@Configuration
@EnableAsync
public class SyncConfiguration {

}

步驟2:在方法標(biāo)記為異步調(diào)用

增加一個ScoreService類,用于積分處理暑始。
@Async添加在方法上搭独,代表該方法為異步處理。

@Service
public class ScoreService {

    private static final Logger logger = LoggerFactory.getLogger(ScoreService.class);

    @Async
    public void addScore(){
        //TODO 模擬睡10秒廊镜,用于贈送積分處理
        try {
            Thread.sleep(1000*10);
            logger.info("--------------處理積分--------------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

添加一個測試類牙肝,TestController

@RestController
public class TestController {

    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @Autowired
    private ScoreService scoreService;

    @RequestMapping("/sync")
    public  String  createUser() {
        logger.info("--------------注冊用戶--------------------");
        this.scoreService.addScore();
        return "OK";
    }
}

步驟3:體驗效果

在瀏覽器輸入:http://127.0.0.1:9090/sync


從日志的截圖可以看出2點:

  1. 異步日志相隔10s
  2. 不同的線程,線程[nio-9090-exec-1]代表的是tomcat的線程嗤朴,線程[task-1]代表的是異步Async的線程

五配椭、為什么要給Async自定義線程池?

@Async注解雹姊,在默認(rèn)情況下用的是SimpleAsyncTaskExecutor線程池股缸,該線程池不是真正意義上的線程池,因為線程不重用吱雏,每次調(diào)用都會新建一條線程敦姻。
可以通過控制臺日志輸出查看,每次打印的線程名都是[task-1]歧杏、[task-2]镰惦、[task-3]、[task-4].....遞增的犬绒。

@Async注解異步框架提供多種線程

SimpleAsyncTaskExecutor:不是真的線程池旺入,這個類不重用線程,每次調(diào)用都會創(chuàng)建一個新的線程懂更。

SyncTaskExecutor:這個類沒有實現(xiàn)異步調(diào)用眨业,只是一個同步操作。只適用于不需要多線程的地方

ConcurrentTaskExecutor:Executor的適配類沮协,不推薦使用龄捡。如果ThreadPoolTaskExecutor不滿足要求時,才用考慮使用這個類

ThreadPoolTaskScheduler:可以使用cron表達(dá)式

ThreadPoolTaskExecutor :最常使用慷暂,推薦聘殖。 其實質(zhì)是對java.util.concurrent.ThreadPoolExecutor的包裝

六、為@Async實現(xiàn)一個自定義線程池

步驟1:配置線程池

@Configuration
@EnableAsync
public class SyncConfiguration {
    @Bean(name = "scorePoolTaskExecutor")
    public ThreadPoolTaskExecutor getScorePoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //核心線程數(shù)
        taskExecutor.setCorePoolSize(10);
        //線程池維護(hù)線程的最大數(shù)量,只有在緩沖隊列滿了之后才會申請超過核心線程數(shù)的線程
        taskExecutor.setMaxPoolSize(100);
        //緩存隊列
        taskExecutor.setQueueCapacity(50);
        //許的空閑時間,當(dāng)超過了核心線程出之外的線程在空閑時間到達(dá)之后會被銷毀
        taskExecutor.setKeepAliveSeconds(200);
        //異步方法內(nèi)部線程名稱
        taskExecutor.setThreadNamePrefix("score-");
        /**
         * 當(dāng)線程池的任務(wù)緩存隊列已滿并且線程池中的線程數(shù)目達(dá)到maximumPoolSize行瑞,如果還有任務(wù)到來就會采取任務(wù)拒絕策略
         * 通常有以下四種策略:
         * ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常奸腺。
         * ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常血久。
         * ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務(wù)突照,然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
         * ThreadPoolExecutor.CallerRunsPolicy:重試添加當(dāng)前的任務(wù),自動重復(fù)調(diào)用 execute() 方法氧吐,直到成功
         */
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
                taskExecutor.initialize();
                return taskExecutor;
    }
}

步驟2:為@Async指定線程池

@Async("scorePoolTaskExecutor")
public void addScore2(){
    //TODO 模擬睡5秒讹蘑,用于贈送積分處理
    try {
        Thread.sleep(1000*5);
        logger.info("--------------處理積分--------------------");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

以上代碼挺簡單的末盔,就是給@Async("scorePoolTaskExecutor")加個參數(shù)即可。

@RequestMapping("/sync2")
public  String  createUser2() {
    logger.info("--------------注冊用戶2--------------------");
    this.scoreService.addScore2();
    return "OK";
}

步驟3:體驗效果

在瀏覽器輸入:http://127.0.0.1:9090/sync2

2019-09-17 16:25:06.128  INFO 47776 --- [nio-9090-exec-1] com.agan.boot.controller.TestController  : --------------注冊用戶2--------------------
2019-09-17 16:25:11.136  INFO 47776 --- [        score-1] com.agan.boot.service.ScoreService       : --------------處理積分--------------------

從日志的可以看出:
線程[score-1]代表的是我們自定義的線程池score線程

七座慰、課后練習(xí)

在現(xiàn)實的互聯(lián)網(wǎng)項目開發(fā)中陨舱,針對高并發(fā)的請求,一般的做法是高并發(fā)接口單獨線程池隔離處理版仔。

假設(shè)現(xiàn)在2個高并發(fā)接口:

一個是修改用戶信息接口游盲,刷新用戶redis緩存.

一個是下訂單接口,發(fā)送app push信息.

請參考本課程內(nèi)容蛮粮,設(shè)計2個線程池益缎,分別用于[刷新用戶redis緩存]和[發(fā)送app push信息]

-----------------------------配套學(xué)習(xí)資料-----------------------------

  1. 課后練習(xí)作業(yè)請?zhí)峤坏絈Q群(1號QQ群3000人已滿,請加2號群:985378659[群名:SpringBoot架構(gòu)師])
  2. 本課程配套免費視頻教程
    https://study.163.com/course/introduction/1004576013.htm?share=1&shareId=1016481220
  3. 本課程配套源碼地址:https://github.com/agan-java/agan-boot
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝉揍,一起剝皮案震驚了整個濱河市链峭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌又沾,老刑警劉巖弊仪,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杖刷,居然都是意外死亡励饵,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門滑燃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來役听,“玉大人,你說我怎么就攤上這事表窘〉溆瑁” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵乐严,是天一觀的道長瘤袖。 經(jīng)常有香客問我,道長昂验,這世上最難降的妖魔是什么捂敌? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮既琴,結(jié)果婚禮上占婉,老公的妹妹穿的比我還像新娘。我一直安慰自己甫恩,他們只是感情好逆济,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般奖慌。 火紅的嫁衣襯著肌膚如雪霎终。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天升薯,我揣著相機(jī)與錄音,去河邊找鬼击困。 笑死涎劈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的阅茶。 我是一名探鬼主播蛛枚,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼脸哀!你這毒婦竟也來了蹦浦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤撞蜂,失蹤者是張志新(化名)和其女友劉穎盲镶,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝌诡,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡溉贿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了浦旱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宇色。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖颁湖,靈堂內(nèi)的尸體忽然破棺而出宣蠕,到底是詐尸還是另有隱情,我是刑警寧澤甥捺,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布抢蚀,位于F島的核電站,受9級特大地震影響涎永,放射性物質(zhì)發(fā)生泄漏思币。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一羡微、第九天 我趴在偏房一處隱蔽的房頂上張望谷饿。 院中可真熱鬧,春花似錦妈倔、人聲如沸博投。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毅哗。三九已至听怕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虑绵,已是汗流浹背尿瞭。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留翅睛,地道東北人声搁。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像捕发,于是被迫代替她去往敵國和親疏旨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容