文档章节

spring异步任务处理 @Async的配置和使用【可以提高业务吞吐量】

weiliu007
 weiliu007
发布于 2017/03/24 17:15
字数 1173
阅读 396
收藏 4

    由于公司需要收集移动端的操作事件,用户的每一个操作,都要存下来,我们用mongodb存放操作日志。

这时可以用spring异步任务来处理,可以提快接口的响应时间。做法如下:

在spring的配置文件里面加入下面类容

rejection-policy="DISCARD" 表示 pool-size到了最大,队列也满了,再来任务就直接丢弃,因为这是收集数据,可以丢一些,防止系统崩溃

<!-- 数据收集异步处理的线程池 -->
<task:executor id="dcExecutor" pool-size="15-1000"
		queue-capacity="100" keep-alive="5" rejection-policy="DISCARD" />

<!-- 上下车提醒异步处理的线程池 -->
<task:executor id="remind" pool-size="15-500"
	queue-capacity="1000" keep-alive="5" rejection-policy="DISCARD" />

要调用的方法上面加上注解@Async

@Async("dcExecutor")
public void handleDataCollection(CMDEnum cmdEnum, String json) {
		switch (cmdEnum) {
		case ROUTE_DETAIL:
			RouteDetail routeDetail = JSON.parseObject(json, RouteDetail.class);
			save(routeDetail, cmdEnum.tableName());
			break;
		case TRANSFER:
			Transfer transfer = JSON.parseObject(json, Transfer.class);
			save(transfer, cmdEnum.tableName());
			break;
		
		default:
			break;
}

总结【基本使用方式】:

@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-20000" queue-capacity="10" />

 <!-- 处理数据收集的线程池 -->
 <task:executor id="dcExecutor" pool-size="15-10000" queue-capacity="50" keep-alive="50/>
@Async("dcExecutor") //如果不指定名字,会使用缺省的“asyncExecutor”  
public void handleDataCollection(CMDEnum cmdEnum, String json) {
		switch (cmdEnum) {
		case ROUTE_DETAIL:
			RouteDetail routeDetail = JSON.parseObject(json, RouteDetail.class);
			save(routeDetail, cmdEnum.tableName());
			break;
		case TRANSFER:
			Transfer transfer = JSON.parseObject(json, Transfer.class);
			save(transfer, cmdEnum.tableName());
			break;
		
		default:
			break;
}

(注意如果在同一个类中调用的话,不会生效,原因请参考:

http://blog.csdn.net/clementad/article/details/47339519

线程的优先级和类型:

优先级: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;
	}

}

 

© 著作权归作者所有

weiliu007
粉丝 16
博文 171
码字总数 84810
作品 0
深圳
程序员
私信 提问
SpringBoot | 第二十一章:异步开发之异步调用

前言 上一章节,我们知道了如何进行异步请求的处理。除了异步请求,一般上我们用的比较多的应该是异步调用。通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的。比如记录日...

oKong
2018/08/17
1K
0
servlet3异步原理与实践

一、什么是Servlet servlet 是基于 Java 的 Web 组件,由容器进行管理,来生成动态内容。像其他基于 Java 的组件技术一样,servlet 也是基于平台无关的 Java 类格式,被编译为平台无关的字节...

新栋BOOK
2017/10/24
1K
5
servlet3异步原理与实践

一、什么是Servlet servlet 是基于 Java 的 Web 组件,由容器进行管理,来生成动态内容。像其他基于 Java 的组件技术一样,servlet 也是基于平台无关的 Java 类格式,被编译为平台无关的字节...

新栋BOOK
2017/10/23
0
0
SpringBoot | 第二十章:异步开发之异步请求

前言 关于的相关知识点,后续有补充时再开续写了。比如服务、等,这些一般上觉得不完全属于方面的,而且目前作为一个接口来提供服务的机会应该比较小了吧。所以本章节开始,开始讲解关于异步...

oKong
2018/08/16
1K
1
Spring task的异步定时任务

背景 有时候,我们需要一些定时任务,帮助我们完成一些日常的操作,从而让我们从琐碎的工作解脱出来,这里使用Spring Task定时异步任务来处理。 步骤 配置命名空间 配置Spring Task Note:这里...

亚林瓜子
2018/06/12
64
0

没有更多内容

加载失败,请刷新页面

加载更多

mysql-connector-java升级到8.0后保存时间到数据库出现了时差

在一个新项目中用到了新版的mysql jdbc 驱动 <dependency>     <groupId>mysql</groupId>     <artifactId>mysql-connector-java</artifactId>     <version>8.0.18</version> ......

ValSong
31分钟前
4
0
Spring Boot 如何部署到 Linux 中的服务

打包完成后的 Spring Boot 程序如何部署到 Linux 上的服务? 你可以参考官方的有关部署 Spring Boot 为 Linux 服务的文档。 文档链接如下: https://docs.ossez.com/spring-boot-docs/docs/r...

honeymoose
33分钟前
5
0
Spring Boot 2 实战:使用 Spring Boot Admin 监控你的应用

1. 前言 生产上对 Web 应用 的监控是十分必要的。我们可以近乎实时来对应用的健康、性能等其他指标进行监控来及时应对一些突发情况。避免一些故障的发生。对于 Spring Boot 应用来说我们可以...

码农小胖哥
今天
6
0
ZetCode 教程翻译计划正式启动 | ApacheCN

原文:ZetCode 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远。 ApacheCN 学习资源 贡献指南 本项目需要校对,欢迎大家提交 Pull Request。 ...

ApacheCN_飞龙
今天
4
0
CSS定位

CSS定位 relative相对定位 absolute绝对定位 fixed和sticky及zIndex relative相对定位 position特性:css position属性用于指定一个元素在文档中的定位方式。top、right、bottom、left属性则...

studywin
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部