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


這個注解用於標注某個方法或某個類里面的全部方法都是須要異步處理的。被注解的方法被調用的時候。會在新線程中運行,而調用它的方法會在原來的線程中運行。

這樣能夠避免堵塞、以及保證任務的實時性。適用於處理log、發送郵件、短信……等。


注解的應用范圍:
  • 類:表示這個類中的全部方法都是異步的
  • 方法:表示這種方法是異步的,假設類也注解了。則以這種方法的注解為准

相關的配置:
<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"/>

實例:
 <!-- 缺省的異步任務線程池 --> 
 <task:annotation-driven executor="asyncExecutor" />
 <task:executor id="asyncExecutor" pool-size="100-10000" queue-capacity="10" />

 <!-- 處理log的線程池 -->
 <task:executor id="logExecutor" pool-size="15-1000" queue-capacity="5" keep-alive="5"/>

 @Override
 @Async("logExecutor")    //假設不指定名字。會使用缺省的“asyncExecutor”
 public void saveUserOpLog(TabUserOpLog tabUserOpLog) {
 
  userOpLogDAO.insertTabUserOpLog(tabUserOpLog);
 }
(注意:假設在同一個類中調用的話。不會生效,原因請參考: 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編程方式的配置方法:
@Configuration
@EnableAsync
public class SpringConfig {

	/** 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;

	private String ThreadNamePrefix = "MyLogExecutor-";

	@Bean
	public Executor logExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(corePoolSize);
		executor.setMaxPoolSize(maxPoolSize);
		executor.setQueueCapacity(queueCapacity);
		executor.setThreadNamePrefix(ThreadNamePrefix);

		// rejection-policy:當pool已經達到max size的時候,怎樣處理新任務
		// CALLER_RUNS:不在新線程中運行任務。而是有調用者所在的線程來運行
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.initialize();
		return executor;
	}

}



(原創文章。轉載請注明轉自Clement-Xu的博客:http://blog.csdn.net/clementad/article/details/47403185


免責聲明!

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



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