Spring異步任務處理,@Async的配置和使用

本文轉自http://blog.csdn.net/clementad/article/details/47403185 感謝做者html

這個註解用於標註某個方法或某個類裏面的全部方法都是須要異步處理的。被註解的方法被調用的時候,會在新線程中執行,而調用它的方法會在原來的線程中執行。這樣能夠避免阻塞、以及保證任務的實時性。適用於處理log、發送郵件、短信……等。java

註解的應用範圍:
  • 類:表示這個類中的全部方法都是異步的
  • 方法:表示這個方法是異步的,若是類也註解了,則以這個方法的註解爲準
 
相關的配置:
<task:annotation-driven />配置:
  • executor:指定一個缺省的executor給@Async使用。
例子:
<task:annotation-driven executor="asyncExecutor" />
 
<task:executor />配置參數:
  • id:當配置多個executor時,被@Async("id")指定使用;也被做爲線程名的前綴。
  • pool-size
    • core size:最小的線程數,缺省:1
    • max size:最大的線程數,缺省:Integer.MAX_VALUE
  • queue-capacity:當最小的線程數已經被佔用滿後,新的任務會被放進queue裏面,當這個queue的capacity也被佔滿以後,pool裏面會建立新線程處理這個任務,直到總線程數達到了max size,這時系統會拒絕這個任務並拋出TaskRejectedException異常(缺省配置的狀況下,能夠經過rejection-policy來決定如何處理這種狀況)。缺省值爲:Integer.MAX_VALUE
  • keep-alive:超過core size的那些線程,任務完成後,再通過這個時長(秒)會被結束掉
  • rejection-policy:當pool已經達到max size的時候,如何處理新任務
    • ABORT(缺省):拋出TaskRejectedException異常,而後不執行
    • DISCARD:不執行,也不拋出異常
    • DISCARD_OLDEST:丟棄queue中最舊的那個任務
    • CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行
 
配置例子:
 <task:annotation-driven executor="asyncExecutor" />
 <task:executor id="asyncExecutor" pool-size="100-10000" queue-capacity="10"/>
 
實例:
[html]  view plain  copy
 
  1. <!-- 缺省的異步任務線程池 -->   
  2. <task:annotation-driven executor="asyncExecutor" />  
  3. <task:executor id="asyncExecutor" pool-size="100-10000" queue-capacity="10" />  
  4.   
  5. <!-- 處理log的線程池 -->  
  6. <task:executor id="logExecutor" pool-size="15-1000" queue-capacity="5" keep-alive="5"/>  

[java]  view plain  copy
 
  1. @Override  
  2. @Async("logExecutor")    //若是不指定名字,會使用缺省的「asyncExecutor」  
  3. public void saveUserOpLog(TabUserOpLog tabUserOpLog) {  
  4.   
  5.  userOpLogDAO.insertTabUserOpLog(tabUserOpLog);  
  6. }  
(注意:若是在同一個類中調用的話,不會生效,緣由請參考: http://blog.csdn.net/clementad/article/details/47339519
 
經過log能夠看到,已經分開兩個線程執行:
 
線程的優先級和類型:
優先級:NORM_PRIORITY
類型:非守護線程
 
用戶線程(User Thread):JVM會等待全部的用戶線程結束後才退出;當系統中沒有用戶線程了,JVM也就退出了
守護線程(Daemon Thread):通常是爲其餘線程提供服務的線程,好比GC垃圾回收器;JVM退出時,不會管守護線程是否存在,而是直接退出
因此,對於文件、數據庫的操做,不適宜使用守護線程,否則可能會丟失數據!
 
Web應用中止時,Spring容器會被關閉,調用者若是是Spring bean,就會中止生成新任務。然而,線程池中已經在運行的任務,因爲缺省是用戶線程,因此JVM會等待它們結束後才退出。
 
附:Java編程方式的配置方法:
[java]  view plain  copy
 
  1. @Configuration  
  2. @EnableAsync  
  3. public class SpringConfig {  
  4.   
  5.     /** Set the ThreadPoolExecutor's core pool size. */  
  6.     private int corePoolSize = 10;  
  7.     /** Set the ThreadPoolExecutor's maximum pool size. */  
  8.     private int maxPoolSize = 200;  
  9.     /** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */  
  10.     private int queueCapacity = 10;  
  11.   
  12.     private String ThreadNamePrefix = "MyLogExecutor-";  
  13.   
  14.     @Bean  
  15.     public Executor logExecutor() {  
  16.         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();  
  17.         executor.setCorePoolSize(corePoolSize);  
  18.         executor.setMaxPoolSize(maxPoolSize);  
  19.         executor.setQueueCapacity(queueCapacity);  
  20.         executor.setThreadNamePrefix(ThreadNamePrefix);  
  21.   
  22.         // rejection-policy:當pool已經達到max size的時候,如何處理新任務  
  23.         // CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行  
  24.         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());  
  25.         executor.initialize();  
  26.         return executor;  
  27.     }  
  28.   
  29. }  
相關文章
相關標籤/搜索