1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        SpringBoot異步調用Async,怎么搞?

        共 5301字,需瀏覽 11分鐘

         ·

        2020-10-26 18:49

        點擊上方藍色字體,選擇“標星公眾號”

        優(yōu)質文章,第一時間送達

        ? 作者?|??47號Gamer丶

        來源 |? urlify.cn/qMreiy

        66套java從入門到精通實戰(zhàn)課程分享

        異步調用相對于同步調用而言,通常的方法都是程序按照順序來執(zhí)行的,程序的每一步都需要等到上一步執(zhí)行完成之后才能繼續(xù)往下執(zhí)行;而異步調用則無需等待,它可以在不阻塞主線程的情況下執(zhí)行高耗時方法

        實現(xiàn)異步調用

        1、在主類中添加@EnableAsync注解

        @EnableAsync
        @SpringBootApplication
        public?class?WebMvcApplication?{
        ????public?static?void?main(String[]?args){
        ????????SpringApplication?app?=?new?SpringApplication(WebMvcApplication.class);
        ????????app.run(args);
        ????}
        }

        2、創(chuàng)建一個AsyncTask類

        在里面添加兩個用@Async注解的task

        @Component
        @Slf4j
        public?class?AsyncTask?{
        ????@Async
        ????public?Future?doTask1()?throws?InterruptedException{
        ????????log.info("Task1?started.");
        ????????long?start?=?System.currentTimeMillis();
        ????????Thread.sleep(5000);
        ????????long?end?=?System.currentTimeMillis();
        ????????log.info("Task1?finished,?time?elapsed:?{}?ms.",?end-start);
        ????????return?new?AsyncResult<>("Task1?accomplished!");
        ????}

        ????@Async
        ????public?Future?doTask2()?throws?InterruptedException{
        ????????log.info("Task2?started.");
        ????????long?start?=?System.currentTimeMillis();
        ????????Thread.sleep(3000);
        ????????long?end?=?System.currentTimeMillis();
        ????????log.info("Task2?finished,?time?elapsed:?{}?ms.",?end-start);
        ????????return?new?AsyncResult<>("Task2?accomplished!");
        ????}
        }

        調用:

        public?class?AsyncController?{

        ????@Autowired
        ????private?AsyncTask?asyncTask;

        ????@RequestMapping(value?=?"/async",method?=?RequestMethod.GET)
        ????public?String?task()?throws?InterruptedException,?ExecutionException?{
        ????????Long?time?=?System.currentTimeMillis();
        ????????Future?task1?=?asyncTask.doTask1();
        ????????Future?task2?=?asyncTask.doTask2();

        ????????while(true)?{
        ????????????if(task1.isDone()?&&?task2.isDone())?{
        ????????????????log.info("Task1?result:?{}",?task1.get());
        ????????????????log.info("Task2?result:?{}",?task2.get());
        ????????????????break;
        ????????????}
        ????????????Thread.sleep(1000);
        ????????}
        ????????log.info("耗時:{}?ms",System.currentTimeMillis()-time);
        ????????return?"success";
        ????}
        }

        Future接口:

        用于獲取異步計算的結果,可通過get()獲取結果、cancel()取消、isDone()判斷是否完成等操作。

        • V get():獲取結果,若無結果會阻塞至異步計算完成

        • V get(long timeOut, TimeUnit unit):獲取結果,超時返回null

        • boolean isDone():執(zhí)行結束(完成/取消/異常)返回true

        • boolean isCancelled():任務完成前被取消返回true

        • boolean cancel(boolean mayInterruptRunning):取消任務,未開始或已完成返回false,參數(shù)表示是否中斷執(zhí)行中的線程。Future.cancel(true)適用于長時間處于運行的任務,并且能夠處理interruption 。

        執(zhí)行結果:

        2019-12-20?15:52:44.685??INFO?9240?---?[?????????task-2]:?Task2?started.
        2019-12-20?15:52:44.685??INFO?9240?---?[?????????task-1]:?Task1?started.
        2019-12-20?15:52:47.685??INFO?9240?---?[?????????task-2]:?Task2?finished,?time?elapsed:?3000?ms.
        2019-12-20?15:52:49.685??INFO?9240?---?[?????????task-1]:?Task1?finished,?time?elapsed:?5000?ms.
        2019-12-20?15:52:49.686??INFO?9240?---?[nio-7091-exec-1]:?Task1?result:?Task1?accomplished!
        2019-12-20?15:52:49.686??INFO?9240?---?[nio-7091-exec-1]:?Task2?result:?Task2?accomplished!
        2019-12-20?15:52:49.686??INFO?9240?---?[nio-7091-exec-1]:?耗時:5007?ms

        自定義的Executor:

        @Configuration
        @EnableAsync
        public?class?ExecutorConfig?{

        ????/**?Set?the?ThreadPoolExecutor's?core?pool?size.?*/
        ????private?int?corePoolSize?=?10;
        ????/**?Set?the?ThreadPoolExecutor'
        s?maximum?pool?size.?*/
        ????private?int?maxPoolSize?=?200;
        ????/**?Set?the?capacity?for?the?ThreadPoolExecutor's?BlockingQueue.?*/
        ????private?int?queueCapacity?=?10;

        ????@Bean("taskExecutor")
        ????public?Executor?taskExecutor()?{
        ????????ThreadPoolTaskExecutor?executor?=?new?ThreadPoolTaskExecutor();
        ????????executor.setCorePoolSize(corePoolSize);
        ????????executor.setMaxPoolSize(maxPoolSize);
        ????????executor.setQueueCapacity(queueCapacity);
        ????????executor.setThreadNamePrefix("default-");
        ????????executor.initialize();
        ????????return?executor;
        ????}

        ????@Bean
        ????public?Executor?myAsync()?{
        ????????ThreadPoolTaskExecutor?executor?=?new?ThreadPoolTaskExecutor();
        ????????executor.setCorePoolSize(corePoolSize);
        ????????executor.setMaxPoolSize(maxPoolSize);
        ????????executor.setQueueCapacity(queueCapacity);
        ????????executor.setKeepAliveSeconds(60);
        ????????executor.setThreadNamePrefix("MyExecutor-");

        ????????// rejection-policy:當pool已經(jīng)達到max size的時候,如何處理新任務
        ????????// CALLER_RUNS:不在新線程中執(zhí)行任務,而是有調用者所在的線程來執(zhí)行
        ????????executor.setRejectedExecutionHandler(new?ThreadPoolExecutor.CallerRunsPolicy());
        ????????executor.initialize();
        ????????return?executor;
        ????}

        }
        • 核心線程數(shù)10:線程池創(chuàng)建時候初始化的線程數(shù)

        • 最大線程數(shù)200:線程池最大的線程數(shù),只有在緩沖隊列滿了之后才會申請超過核心線程數(shù)的線程

        • 緩沖隊列10:用來緩沖執(zhí)行任務的隊列

        • 允許線程的空閑時間60秒:當超過了核心線程出之外的線程在空閑時間到達之后會被銷毀

        • 線程池名的前綴:設置好了之后可以方便我們定位處理任務所在的線程池

        • 線程池對拒絕任務的處理策略:這里采用了CallerRunsPolicy策略,當線程池沒有處理能力的時候,該策略會直接在 execute 方法的調用線程中運行被拒絕的任務;如果執(zhí)行程序已關閉,則會丟棄該任務

        自定義Executor的類名,放進@Async注解中:

        public?class?AsyncTask?{
        ????@Async("myAsync")
        ????public?Future?doTask1()?throws?InterruptedException{

        ????}

        ????@Async
        ????public?Future?doTask2()?throws?InterruptedException{

        ????}
        }

        沒類加類名的@Async注解,會使用 @Bean(“taskExecutor”)的Executor。

        需要注意的問題:

        需要注意的問題一:異步方法的定義位置問題

        最好將異步調用的方法單獨放在一個@Component類中,或者說不要將異步調用方法寫在@Controller中,否則將無法進行調用,因為SpringBoot使用@Transaction需要經(jīng)過事務攔截器,只有通過了該事務攔截器的方法才能被加入Spring的事務管理器中,而在同一個類中的一個方法調用另一個方法只會經(jīng)過一次事務攔截器,所以如果是后面的方法使用了事務注解將不會生效,在這里異步調用也是同樣的道理

        需要注意的問題二:異步方法的事務調用問題

        在@Async注解的方法上再使用@Transaction注解是無效的,在@Async注解的方法中調用Service層的事務方法是有效的

        需要注意的問題三:異步方法必須是實例的

        因為靜態(tài)方法不能被override重寫,因為@Async異步方法的實現(xiàn)原理是通過注入一個代理類到Bean中,該代理類集成這個Bean并且需要重寫這個異步方法,所以需要是實例方法





        粉絲福利:108本java從入門到大神精選電子書領取

        ???

        ?長按上方鋒哥微信二維碼?2 秒
        備注「1234」即可獲取資料



        感謝點贊支持下哈?

        瀏覽 32
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产黄片视频在线观看 | 人体美媚馆无码专区 | 台湾gay无套gaygay无套 | 成人精品无码免费视频 | 国产又爽 又黄 免费动漫 | 欧美性猛交乱大交极品 | 日韩最新高清无码 | 狠狠色婷婷久久一区二区牛牛影视 | 18禁成人无套内射无码免费 | 中国操逼视频 |