Spring异步任务处理,@Async的配置和使用

这个注解用于标注某个方法或某个类里面的所有方法都是需要异步处理的。被注解的方法被调用的时候。会在新线程中运行,而调用它的方法会在原来的线程中运行。

这样可以避免堵塞、以及保证任务的实时性。适用于处理log、发送邮件、短信……等。html


注解的应用范围:
  • 类:表示这个类中的所有方法都是异步的
  • 方法:表示这种方法是异步的,假设类也注解了。则以这种方法的注解为准

相关的配置:
<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


附: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
相关文章
相关标签/搜索