spring異步執行---@Aysnc


   大多數時候處理業務都是以同步的方式來實現的。但在有些特殊的場景中,需要用異步的方式來實現。

  1、最原始的實現異步的方式:單獨起一個線程。缺點在於:異步處理業務太多時,同時運行的線程太多,可能導致服務器崩潰。

  2、然后,出現了線程池,線程池對線程數量進行控制和對線程進行復用,解決了上面的問題。

  3、在2中,程序員需要自己編寫一個線程,然后交給線程池管理。spring為了簡化程序員的代碼,內置了@Async注解,程序員只需編寫純業務代碼和設置自己的線程池即可。

       基於@Async標注的⽅法,稱之為異步⽅法;這些⽅法將在執⾏的時候,將會在獨⽴的線程中被執⾏,調⽤者⽆需等待它的完成,即可繼續其他的操作。

 

如何使用:

  1、在應用中用@EnableAsync注解來啟用@Aysnc注解。可以在spring⼊⼝類加,也可以在需要調⽤異步⽅法的類上加,也可以在應用配置類上加。

  

 

 

   2、在需要異步的方法上加@Aysnc。如果加在類上,相當於這個類的所有方法都加了@Aysnc,那么這個類所有的⽅法都是異步執⾏的。

public class AysncTask {

    /**
     * taskA()被調用時,該方法會被異步執行:會將任務交給線程池去完成
     */
    @Async
    public void taskA() {
        System.out.println("AAAAAAAA");
    }
    
    public void taskB() {
        System.out.println("BBBBBBBBBBB");
    }
}
@Async
public class AysncTask {

    /**
     * taskA()被調用時,該方法會被異步執行:會將任務交給線程池去完成
     */
    public void taskA() {
        System.out.println("AAAAAAAA");
    }
    
    /**
     * taskB()被調用時,該方法會被異步執行:會將任務交給線程池去完成
     */
    public void taskB() {
        System.out.println("BBBBBBBBBBB");
    }
}

  3、如果在@Aysnc中沒有指定線程池,會默認使用spring提供的默認線程池SimpleAsyncTaskExecutor

    缺點:線程池為每個任務都單獨創建一個線程,不會重用線程。這樣,就跟最原始實現異步的方式有了相同的缺點:異步處理業務太多時,同時運行的線程太多,可能導致服務器崩潰。

    因此,我們一定要創建自己的線程池,並給異步任務指定到哪個線程池去執行。

    創建線程池:

@Configuration
public class ExecutorConfig {

    @Bean
    public Executor asyncServiceExecutor() {
        log.info("開始線程池:asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心線程數
        executor.setCorePoolSize(50);
        //配置最大線程數
        executor.setMaxPoolSize(100);
        //配置隊列大小
        executor.setQueueCapacity(99999);
        //配置線程池中的線程的名稱前綴
        executor.setThreadNamePrefix("async-service-");
        // 設置拒絕策略:當pool已經達到max size的時候,如何處理新任務
        // CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //執行初始化
        executor.initialize();
        return executor;

    }
}

  為任務指定線程池:

public class AysncTask {

    /**
     * taskA()被調用時,該方法會被異步執行:會將任務交給線程池去完成
     */
    @Async("asyncServiceExecutor")
    public void taskA() {
        System.out.println("AAAAAAAA");
    }
    
    public void taskB() {
        System.out.println("BBBBBBBBBBB");
    }
}

 

使用過程中的其他注意點:

  1、@Aysnc修飾的異步⽅法不能和調⽤此⽅法的方法放在⼀個類⾥⾯。

    如:@Aysnc修改的方法A(),在方法B()里調用方法A()。B()和A()不能在同一個類里。

  2、@Aysnc修飾的異步⽅法上加@Transactional將無法產生事務管理。因為異步方法單獨開了一個線程導致的。

    解決辦法:將需要做事務管理的代碼單獨寫成一個方法,加上@Transactional,然后在異步調用方法中調用這個方法。

  3、可以為異步方法設置返回值,但必須是java.util.concurrent.Future類型,否則接收不到。如:Future的實現類:AsyncResult、CompletableFuture。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM