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

一文搞懂SpringBoot如何利用@Async實(shí)現(xiàn)異步調(diào)用

 更新時(shí)間:2022年09月08日 14:38:43   作者:老顧聊技術(shù)  
異步調(diào)用幾乎是處理高并發(fā),解決性能問題常用的手段,如何開啟異步調(diào)用?SpringBoot中提供了非常簡單的方式,就是一個(gè)注解@Async。今天我們重新認(rèn)識(shí)一下@Async,以及注意事項(xiàng)

前言

異步調(diào)用幾乎是處理高并發(fā),解決性能問題常用的手段,如何開啟異步調(diào)用?SpringBoot中提供了非常簡單的方式,就是一個(gè)注解@Async。今天我們重新認(rèn)識(shí)一下@Async,以及注意事項(xiàng)

簡單使用

新建三個(gè)作業(yè)任務(wù):

@Service
public class TaskDemo {
    private static Logger logger = LoggerFactory.getLogger(TaskDemo.class);
    public void execute1() {
        logger.info("處理耗時(shí)任務(wù)1......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)1......結(jié)束");
    }
    public void execute2() {
        logger.info("處理耗時(shí)任務(wù)2......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)2......結(jié)束");
    }
    public void execute3() {
        logger.info("處理耗時(shí)任務(wù)3......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)3......結(jié)束");
    }
}

測試代碼:

@RestController
public class TaskController {
    @Autowired
    private TaskDemo taskDemo;

    @GetMapping("/task/test")
    public String testTask() {
        taskDemo.execute1();
        taskDemo.execute2();
        taskDemo.execute3();
        return "ok";
    }
}

執(zhí)行后我們可以發(fā)現(xiàn),上面的代碼是同一個(gè)線程的同步執(zhí)行,整體耗時(shí)9秒才完成。

異步處理

springboot的異步,是非常簡單的,加2個(gè)注解即可

@Service
public class TaskDemo {

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

    @Async
    public void execute1() {
        logger.info("處理耗時(shí)任務(wù)1......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)1......結(jié)束");
    }

    @Async
    public void execute2() {
        logger.info("處理耗時(shí)任務(wù)2......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)2......結(jié)束");
    }

    @Async
    public void execute3() {
        logger.info("處理耗時(shí)任務(wù)3......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)3......結(jié)束");
    }

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

增加了@Async和@EnableAsync兩個(gè)注解

從執(zhí)行結(jié)果發(fā)現(xiàn),整個(gè)流程用了3秒,以及用了3個(gè)線程執(zhí)行。完成了異步調(diào)用

異步回調(diào)

有些場景我們需要知道異步處理的任務(wù)什么時(shí)候完成,需要做額外的業(yè)務(wù)處理。如:我們需要在3個(gè)任務(wù)都完成后,提示一下給用戶

@Service
public class TaskDemo {

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

    @Async
    public Future<String> execute1() {
        logger.info("處理耗時(shí)任務(wù)1......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)1......結(jié)束");

        return new AsyncResult<>("任務(wù)1 ok");
    }

    @Async
    public Future<String> execute2() {
        logger.info("處理耗時(shí)任務(wù)2......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)2......結(jié)束");

        return new AsyncResult<>("任務(wù)2 ok");
    }

    @Async
    public Future<String> execute3() {
        logger.info("處理耗時(shí)任務(wù)3......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)3......結(jié)束");

        return new AsyncResult<>("任務(wù)3 ok");
    }
}
@RestController
public class TaskController {

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

    @Autowired
    private TaskDemo taskDemo;

    @GetMapping("/task/test")
    public String testTask() throws InterruptedException {
        Future<String> task1 = taskDemo.execute1();
        Future<String> task2 = taskDemo.execute2();
        Future<String> task3 = taskDemo.execute3();

        while (true){
            if (task1.isDone() && task2.isDone() && task3.isDone()){
                break;
            }
            TimeUnit.SECONDS.sleep(1);
        }

        logger.info(">>>>>>3個(gè)任務(wù)都處理完成");
        return "ok";
    }
}

執(zhí)行結(jié)果發(fā)現(xiàn),在請(qǐng)求線程里面給用戶提示了3個(gè)任務(wù)都處理完成了。

這段代碼主要改變了什么:

1、把具體任務(wù)返回類型改為了Future類型對(duì)象

2、在調(diào)用任務(wù)時(shí),循環(huán)判斷任務(wù)是否處理完

自定義線程池

說到異步處理,一定要考慮到線程池,什么是線程池,小伙伴可自行網(wǎng)補(bǔ)。@Async的線程池定義比較方便,直接上代碼:

@Configuration
public class ThreadPoolConfig {

    @Bean(name = "taskPool01Executor")
    public ThreadPoolTaskExecutor getTaskPool01Executor() {

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

        taskExecutor.initialize();

        return taskExecutor;
    }

    @Bean(name = "taskPool02Executor")
    public ThreadPoolTaskExecutor getTaskPool02Executor() {

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

        taskExecutor.initialize();

        return taskExecutor;
    }

}

定義了2個(gè)線程池Bean

@Service
public class TaskDemo {

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

    @Async("taskPool01Executor")
    public Future<String> execute1() {
        logger.info("處理耗時(shí)任務(wù)1......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)1......結(jié)束");

        return new AsyncResult<>("任務(wù)1 ok");
    }

    @Async("taskPool01Executor")
    public Future<String> execute2() {
        logger.info("處理耗時(shí)任務(wù)2......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)2......結(jié)束");

        return new AsyncResult<>("任務(wù)2 ok");
    }

    @Async("taskPool02Executor")
    public Future<String> execute3() {
        logger.info("處理耗時(shí)任務(wù)3......開始");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("處理耗時(shí)任務(wù)3......結(jié)束");

        return new AsyncResult<>("任務(wù)3 ok");
    }

}

@Async(“線程池名稱”),指定value使用自己定義的線程池:

執(zhí)行結(jié)果利用了線程池。

注意事項(xiàng)(一定注意)

在使用@Async注解時(shí),很多小伙伴都會(huì)發(fā)現(xiàn)異步使用失敗。主要原因是異步方法的定義出了問題。

1、異步方法不能使用static修飾

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

3、異步方法和調(diào)用異步方法的方法不能在同一個(gè)類

4、類中需要使用@Autowired或@Resource等注解自動(dòng)注入,不能自己手動(dòng)new對(duì)象

5、如果使用SpringBoot框架必須在啟動(dòng)類中增加@EnableAsync注解?

到此這篇關(guān)于一文搞懂SpringBoot如何利用@Async實(shí)現(xiàn)異步調(diào)用的文章就介紹到這了,更多相關(guān)SpringBoot @Async異步調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Springboot參數(shù)校驗(yàn)之分組校驗(yàn)、嵌套校驗(yàn)的實(shí)現(xiàn)

    Springboot參數(shù)校驗(yàn)之分組校驗(yàn)、嵌套校驗(yàn)的實(shí)現(xiàn)

    日常開發(fā)中,免不了需要對(duì)請(qǐng)求參數(shù)進(jìn)行校驗(yàn),諸如判空,長度,正則,集合等,復(fù)雜一點(diǎn)的請(qǐng)求參數(shù)可能會(huì)包含嵌套,分組校驗(yàn),本文就詳細(xì)的介紹一下,感興趣的可以了解一下
    2023-08-08
  • 如何用Springboot快速整合shiro安全框架

    如何用Springboot快速整合shiro安全框架

    這篇文章主要介紹了如何用SpringBoot快速整合shiro安全框架,shiro原名Apache Shiro 是一個(gè)Java 的安全(權(quán)限)框架。Shiro 可以非常容易的開發(fā)出足夠好的應(yīng)用,感興趣的同學(xué)可以參考閱讀
    2023-04-04
  • 使用mybatis攔截器處理敏感字段

    使用mybatis攔截器處理敏感字段

    這篇文章主要介紹了mybatis攔截器處理敏感字段方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java中dart類詳細(xì)講解

    java中dart類詳細(xì)講解

    這篇文章主要介紹了dart類詳細(xì)講解,實(shí)例講解的很清晰,有對(duì)于這方面不太清楚的同學(xué)可以跟著學(xué)習(xí)下
    2021-02-02
  • SpringBoot實(shí)現(xiàn)發(fā)送QQ郵件的示例代碼

    SpringBoot實(shí)現(xiàn)發(fā)送QQ郵件的示例代碼

    這篇文章主要介紹了SpringBoot如何實(shí)現(xiàn)發(fā)送QQ郵件功能,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • 一文搞懂Spring中的Bean作用域

    一文搞懂Spring中的Bean作用域

    scope用來聲明容器中的對(duì)象所應(yīng)該處的限定場景或者說該對(duì)象的存活時(shí)間,即容器在對(duì)象進(jìn)入其 相應(yīng)的scope之前,生成并裝配這些對(duì)象,在該對(duì)象不再處于這些scope的限定之后,容器通常會(huì)銷毀這些對(duì)象,這篇文章主要介紹了Spring中的Bean作用域,需要的朋友可以參考下
    2022-06-06
  • SpringAOP實(shí)現(xiàn)自定義接口權(quán)限控制

    SpringAOP實(shí)現(xiàn)自定義接口權(quán)限控制

    本文主要介紹了SpringAOP實(shí)現(xiàn)自定義接口權(quán)限控制,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-11-11
  • SpringBoot創(chuàng)建RSocket服務(wù)器的全過程記錄

    SpringBoot創(chuàng)建RSocket服務(wù)器的全過程記錄

    RSocket應(yīng)用層協(xié)議支持 Reactive Streams語義, 例如:用RSocket作為HTTP的一種替代方案。這篇文章主要給大家介紹了關(guān)于SpringBoot創(chuàng)建RSocket服務(wù)器的相關(guān)資料,需要的朋友可以參考下
    2021-05-05
  • 深入理解Java8新特性之Optional容器類的應(yīng)用

    深入理解Java8新特性之Optional容器類的應(yīng)用

    Optional<T> 類(java.util.Optional) 是一個(gè)容器類,代表一個(gè)值存在或不存在,原來用 null 表示一個(gè)值不存在,現(xiàn)在 Optional 可以更好的表達(dá)這個(gè)概念。并且可以避免空指針異常,需要的朋友可以參考下本文
    2021-11-11
  • Java 實(shí)現(xiàn)隨機(jī)驗(yàn)證碼功能簡單實(shí)例

    Java 實(shí)現(xiàn)隨機(jī)驗(yàn)證碼功能簡單實(shí)例

    這篇文章主要介紹了Java 實(shí)現(xiàn)隨機(jī)驗(yàn)證碼功能簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-04-04

最新評(píng)論