欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解SpringBoot如何開啟異步編程

 更新時間:2023年04月21日 09:12:26   作者:卡蘭  
本文主要介紹了詳解SpringBoot如何開啟異步編程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、什么是異步?

現(xiàn)在我們假設(shè)有一個接口方法,里面又調(diào)用了三個子方法,分別是A,B,C。先從A執(zhí)行,執(zhí)行完畢再執(zhí)行B,B執(zhí)行完最后執(zhí)行C。這也是我們代碼最常見的執(zhí)行方式。ABC順序執(zhí)行,其中一個出問題了,如果拋出了異常,后續(xù)則不再執(zhí)行。這中方式就是同步執(zhí)行。

那么異步執(zhí)行是什么樣子的呢?

假設(shè)B方法改為異步,那么A方法執(zhí)行完畢,執(zhí)行B方法。此時不需要等B方法執(zhí)行完畢,代碼會直接執(zhí)行C方法。也就是B方法不再影響C方法的執(zhí)行,這里B方法就是異步執(zhí)行。

二、為什么要使用異步編程?

異步方法的作用也很明顯,假設(shè)我們上面的接口方法是一個用戶注冊方法,A方法注冊成功,B方法是增加積分,C方法增加權(quán)限。那么A方法執(zhí)行成功后,我們就可以給用戶添加權(quán)限了。至于增加積分,完全可以異步處理,這樣注冊的效率就會更高,提高用戶體驗。實際上的業(yè)務(wù)場景還有很多,通常需要異步的都是執(zhí)行比較慢,又對我們串行執(zhí)行的業(yè)務(wù)邏輯沒有影響,為了提高代碼效率,我們就需要異步執(zhí)行。

三、SpringBoot開啟異步編程

接下來,我們就以SpringBoot項目為例,來看下如何使用異步編程。

第一步,通常來說一個新功能都是從引入包開始,因為這個功能本身是Spring 3提供的功能,所以我們可以直接使用。首先在主啟動類上通過注解@EnableAsync開啟異步功能。

@SpringBootApplication
@EnableAsync
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

第二步,在需要異步的方法上,添加注解@Async,這樣就可以了。

@Async
public void testAsync() {
    xxxx;
}

是不是非常簡單?使用當(dāng)然非常簡單了,但是這里面有許多坑和業(yè)務(wù)場景,我們就來一一說明。

1、有返回值的異步方法

@RestController
public class TestController {
    public Result testAsync(){
        service.testA();
        service.testB();
        service.testC();
        return Result.success();
    }
}

@Service
public class service{
        void testA(){
            xxxx;
        };
        @Async
        void testB(){
        xxxx;
    };
        void testC(){
        xxxx;
    };
}

我們在Controller層的testAsync接口中,分別調(diào)用了service層中的testA,testB,testC方法。其中testB我們加了@Async異步注解,那么在主線程testAsync中執(zhí)行testB就無需等待,會繼續(xù)執(zhí)行testC方法。

如果是沒有返回值的testB方法,那么這樣就可以滿足我們的需求了,但是如果testB有返回值呢,而且需要我們對返回值進(jìn)行存儲。那么就需要有返回值的異步方法。這個也比較簡單,我們只需要使用Future(java.util類中的)來進(jìn)行返回。

@RestController
public class TestController {
    public Result testAsync(){
        service.testA();
        Future future =  service.testB();
        //testC不許等待testB執(zhí)行完畢,即可執(zhí)行
        service.testC();
        //get()會一直等待有結(jié)果返回
        log.info(future.get());
        return Result.success();
    }
}
 @Service
public class service{
        void testA(){
            xxxx;
        };
        @Async
        Future<String> testB(){
        xxxx;
        return new AsyncResult<>("返回值結(jié)果);
    };
        void testC(){
        xxxx;
    };
}

看testB方法,我們改為Future類型的返回。此時就可以獲得異步方法的返回了,但是注意我們這里是異步,所以在使用返回結(jié)果future時,可能是沒有值的,因為我們異步方法可能沒有執(zhí)行完畢。這里需要我們使用future.get()方法獲取返回結(jié)果,get方法會自旋一直等待,直到有返回結(jié)果才繼續(xù)往下執(zhí)行。

這里使用get獲取結(jié)果時要注意了,如果放在testC前面獲取異步結(jié)果,就會導(dǎo)致testC無法串行執(zhí)行,所以一定要根據(jù)業(yè)務(wù)場景來使用。比如我們將獲取testB的結(jié)果放在了最后一行,testC串行執(zhí)行,在最終返回結(jié)果前再獲取異步testB方法的返回結(jié)果。

2、@Async使用的線程池

在使用@Async注解時,你一定從網(wǎng)上看到過許多人說,不要使用默認(rèn)線程池,這個是怎么回事呢?

首先,我們要明白,@Async的異步實現(xiàn),其實就是起一個新的線程,和主線程區(qū)分開,來執(zhí)行異步的方法。這樣你主線程繼續(xù)串行執(zhí)行,我新起的子線程執(zhí)行你的異步方法,互不影響,這樣就實現(xiàn)了異步執(zhí)行的目的。

牽扯到多線程,那就一定離不開線程池的使用,這個在這里不詳細(xì)說,我會在線程池相關(guān)的文章里說明?;氐絼偛诺膯栴},網(wǎng)上許多人說的,不要使用默認(rèn)線程池,是因為@Async以前版本使用的默認(rèn)線程池是SimpleAsyncTaskExecutor,這個線程池有許多問題,推薦使用的都是ThreadPoolTaskExecutor。

實際上,SpringBoot已經(jīng)考慮到這個問題了,在新的版本中@Async默認(rèn)使用的線程池就是ThreadPoolTaskExecutor,這里注意看下你使用的版本。

SpringBoot 2.0.9以及之前的版本,使用的線程池默認(rèn)是SimpleAsyncTaskExecutor,之后默認(rèn)使用的是ThreadPoolTaskExecutor

3、SpringBoot使用的默認(rèn)線程池源碼解析

SpringBoot默認(rèn)使用的是哪個線程池,是如何配置的呢?這一部分,感興趣的可以看下,不感興趣的直接看下一節(jié),配置線程池參數(shù)就可以了。

找到@Async的攔截器方法,每次會先執(zhí)行。

image.png

入?yún)⒌腅xcutor參數(shù)可以是null,如果不是null,就使用指定的Excutor,這個就可以來指定我們自己的Excutor,這個后面說。

image.png

如果入?yún)⑹莕ull,就使用如下方法獲取。這里有三行關(guān)鍵代碼,第一行通過beanFactory.getBean獲取TaskExcutor類型的Bean。但是這里是通過類型獲取的,實現(xiàn)Excutor的如果有多個類,就會報錯,被第二行代碼捕獲,進(jìn)入第三行代碼獲取Bean。第三行通過名字獲取的Bean,名字是taskExcutor。

image.png

image.png

名字是taskExcutor的Bean,是SpringBoot默認(rèn)給我們配置好了的,接著看SpringBoot的自動配置相關(guān)源碼TaskExecutionAutoConfiguration類,紅框里最終配置的Bean名字就是taskExcutor。

image.png

image.png

這里注意這個注解@ConditionalOnMissingBean,只在沒有Excutor實現(xiàn)類的時候,才會默認(rèn)配置。和上面通過beanFactory.getBean獲取TaskExcutor類型的Bean代碼呼應(yīng)起來了。如果我們項目沒有注入Excutor的話,SpringBoot就會默認(rèn)注入ThreadPoolTaskExecutor。如果我們指定了,這樣使用@Async(“myExcutor”)則使用我們指定的。如果沒指定,還有多個實現(xiàn)Bean沖突了,則使用Bean名字是taskExcutor的。

image.png

我們再來看下默認(rèn)線程池配置,創(chuàng)建線程池時使用的都是TaskExecutionProperties這個配置文件。

image.png

我們再來看這個配置文件,紅框處是幾個關(guān)鍵參數(shù)。

image.png

問題非常明顯,有幾個參數(shù)值最大值非常大,Integer.MAX_VALUE。需要我們在使用時根據(jù)業(yè)務(wù)場景進(jìn)行配置,不然存在隱患。

4、線程池配置

首先,我們需要了解線程池的基本運(yùn)行原理,才能更好的配置。這里簡單給大家介紹一下,在后面專門的線程池文章會詳細(xì)說明。

線程池有幾個重要的基本參數(shù),核心線程數(shù),等待隊列,最大線程數(shù)量,線程存活時間等。有新的任務(wù)過來時,先啟用核心線程,核心線程滿了后,再加到等待隊列,等待隊列也滿了后,如果小于最大線程數(shù),則繼續(xù)開啟新的線程,直到達(dá)到最大線程數(shù)量。

所以,上文線程池默認(rèn)配置中,系統(tǒng)默認(rèn)配置的核心線程數(shù)是8,但是等待隊列最大值無上限,這里就不太合適。需要按照業(yè)務(wù)實際使用場景來配置。同時最大線程數(shù)也需要配置,不然資源不夠,起了無限多的線程,就OOM了。

存活時間默認(rèn)60s,也是根據(jù)自己的任務(wù)響應(yīng)時間來配置。allowCoreThreadTimeout是配置核心線程數(shù)是否設(shè)置存活時間的參數(shù),如果配置true,那么核心線程數(shù)存活時間也會生效,空閑時不會一直存在。

配置時可以自己通過代碼設(shè)置,也可以直接在配置文件設(shè)置,下面是簡單參考。

spring:
  task:
    execution:
      pool:
        core-size: 8
        queue-capacity: 100
        max-size: 16
        keep-alive: 60
        allow-core-thread-timeout: false

四、結(jié)語

到這,我們今天的文章就算結(jié)束了,大家跟著文章,應(yīng)該學(xué)會使用異步編程了,能夠滿足大多數(shù)場景的使用了。

當(dāng)然,還有些許多問題因為篇幅問題這里沒提,比如如何寫自己的線程池,除去SpringBoot的異步方式,Java8也給我們提供了異步編程方式CompletableFuture,這個如何使用呢?和SpringBoot提供的注解有何區(qū)別?

到此這篇關(guān)于詳解SpringBoot如何開啟異步編程的文章就介紹到這了,更多相關(guān)SpringBoot異步編程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Java中AC自動機(jī)的原理與實現(xiàn)

    詳解Java中AC自動機(jī)的原理與實現(xiàn)

    AC自動機(jī)是一個多模式匹配算法,在模式匹配領(lǐng)域被廣泛應(yīng)用。本文將詳細(xì)為大家介紹AC自動機(jī)的原理與實現(xiàn)方法,感興趣的可以了解一下
    2022-05-05
  • 通過實例解析POJO和JavaBean的區(qū)別

    通過實例解析POJO和JavaBean的區(qū)別

    這篇文章主要介紹了通過實例解析POJO和JavaBean的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • Spring?MVC概念+項目創(chuàng)建+@RequestMappring案例代碼

    Spring?MVC概念+項目創(chuàng)建+@RequestMappring案例代碼

    Spring?MVC?是?Spring?提供的一個基于?MVC?設(shè)計模式的輕量級?Web?開發(fā)框架,本質(zhì)上相當(dāng)于?Servlet,這篇文章主要介紹了Spring?MVC概念+項目創(chuàng)建+@RequestMappring,需要的朋友可以參考下
    2023-02-02
  • java springmvc亂碼解決歸納整理詳解

    java springmvc亂碼解決歸納整理詳解

    本篇文章介紹了java 中spring mvc 解決亂碼的問題方法實例,需要的朋友可以參考下
    2017-04-04
  • 手把手搭建Java共享網(wǎng)盤的方法步驟

    手把手搭建Java共享網(wǎng)盤的方法步驟

    這篇文章主要介紹了手把手搭建Java共享網(wǎng)盤,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java SpringBoot的相關(guān)知識點詳解

    Java SpringBoot的相關(guān)知識點詳解

    這篇文章主要介紹了SpringBoot的相關(guān)知識點,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2021-10-10
  • 在Android系統(tǒng)中使用WebViewClient處理跳轉(zhuǎn)URL的方法

    在Android系統(tǒng)中使用WebViewClient處理跳轉(zhuǎn)URL的方法

    這篇文章主要介紹了在Android系統(tǒng)中使用WebViewClient處理跳轉(zhuǎn)URL的方法,實現(xiàn)代碼為Java語言編寫,是需要的朋友可以參考下
    2015-07-07
  • java性能優(yōu)化之分代回收

    java性能優(yōu)化之分代回收

    這篇文章主要介紹了java性能優(yōu)化之分代回收,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-07-07
  • 一篇文章帶你了解JAVA結(jié)構(gòu)化編程詳情

    一篇文章帶你了解JAVA結(jié)構(gòu)化編程詳情

    下面小編就為大家?guī)硪黄v解JAVA結(jié)構(gòu)化編程的文章。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-09-09
  • Java用鄰接表存儲圖的示例代碼

    Java用鄰接表存儲圖的示例代碼

    鄰接表是圖的一種鏈?zhǔn)酱鎯Ψ椒ǎ鋽?shù)據(jù)結(jié)構(gòu)包括兩部分:節(jié)點和鄰接點。本文將用鄰接表實現(xiàn)存儲圖,感興趣的小伙伴可以了解一下
    2022-06-06

最新評論