Spring中的@Async註解 異步任務處理

使用需求

在開發中,我們往往有一些特殊的需求,例如log、郵件、用戶op的記錄、來訪者信息的記錄等等。如果將這些操作放在他自己的線程中執行,會不會對程序造成阻塞呢?當高併發的情況下,任務的實時性還存在麼?

@Async

Spring中爲我們提供了@Async註解,異步的去處理。那如何去理解呢?
如果一個方法上加了@Async註解,表明這個方法將由一個新線程區執行而調用他的方法還在原線程執行,就好比去單獨啓用了一個服務去做記錄,而不是在原方法中執行記錄

注:加在類上代表該類中所有方法都爲異步,若方法也加了該註解,以方法的配置爲準

配置

<!--&lt;!&ndash;開啓註解調度支持 @Async @Scheduled&ndash;&gt;-->
    <task:annotation-driven proxy-target-class="true"/>

其中的proxy-target-class=”true”表示要使用一個指定的類,讓Spring來生成它的bean,並使用他的某個方法,“true”或“false”決定是基於接口還是基於類的代理被創建,當true時基於類,默認爲false

還包含其他屬性

//指定一個省缺的執行器
executor="asyncExecutor"  

task:executor的配置參數

//用@Async("loggerExecutor")來指定
id="loggerExecutor"

//池大小
pool-size = "20-1000"

//隊列容量 決定了當任務達到多少時,pool創建新的線程去處理任務
queue-capacity="5"

//最大線程數
max size = "10"
//最小線程數
core size = "5"

//當那些超過coresize的任務完成後 存活時間
keep-alive = "5"

//當達到最大線程數時如何處理
rejection-policy  省缺爲拋出TaskRejectedException異常,然後不執行

使用

異步方法

 @Async
    public void eventPlay(String uniPassportId,
                             String majorCode,
                             String courseCode,
                             String lessonCode,
                             String kpCode,
                             String videoCode,
                             String majorTitle,
                             String lessonTitle,
                             String stageTitle,
                             String kpTitle,
                             String videoPlayUrl,
                             String videoFileName,
                             String playCnt,
                             String playVideoTime) {

        PlayVideoRecordEntity record = new PlayVideoRecordEntity();
        record.setMajorCode(majorCode);
        record.setStageCode(courseCode);
        record.setLessonCode(lessonCode);
        record.setKpCode(kpCode);
        record.setVideoCode(videoCode);
        record.setMajorTitle(majorTitle);
        record.setLessonTitle(lessonTitle);
        record.setStageTitle(stageTitle);
        record.setKpTitle(kpTitle);
        record.setVideoPlayUrl(videoPlayUrl);
        record.setVideoFileName(videoFileName);
        record.setUniPassportId(uniPassportId);
        record.setPlayCnt(playCnt);
        record.setPlayTotalDuration(playVideoTime);
        event(record);

    }

原方法的調用片段

 if (StringUtils.equals(eventType, "videoStart")) {
                event.eventPlay(String.valueOf(userId), majorCode, stageCode, lessonCode, kpCode, videoCode, majorTitle, lessonTitle, stageTitle, kpTitle, videourl, videoFileName, "1", null);
            } else if (StringUtils.equals(eventType, "videoStop")) {
                event.eventPlay(String.valueOf(userId), majorCode, stageCode, lessonCode, kpCode, videoCode, majorTitle, lessonTitle, stageTitle, kpTitle, videourl, videoFileName, null, playVideoTime);
            }

返回值

@Async同樣可以有返回值 類型爲AsyncResult實現了Future接口

public void testAsyncAnnotationForMethodsWithReturnType()  
   throws InterruptedException, ExecutionException {  
    System.out.println("Invoking an asynchronous method. "  
      + Thread.currentThread().getName());  
    Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();  
   //循環掃描該異步方法的執行情況
    while (true) {  
    //用isDone來判斷是否執行完畢
        if (future.isDone()) { 
        // 完畢輸出
            System.out.println( future.get());  
            break;  
        }  
       Thread.sleep(1000);
    }  
}  

總結:這篇只是淺顯的介紹,該註解涉及的問題還有很多,包括像異步情況下如何去處理異常問題,異步的情況下,無法捕捉到異步線程的異常,還有再異步的情況下如何去做事務的管理等等 。 以後用到了更新。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章