实现Spring中的任务调度及异步执行

    首先要端正一下本人的态度,开发了很长时间的Java Web项目,寄托于Spring MVC的架构,多数时间都是在处理业务逻辑问题,所以我个人单纯地认为Web开发,多线程的应用场景应该不多,能不用尽量不用(当然,有这样的想法,那也是我个人多线程运用不多,理解不是很深刻,而且多线程并发操作需要面对和处理的问题很多,像共享资源上锁等)。但现在需要用到了,才明白多线程的应用场景是多么的重要。所以这几天开始在多线程方面进行了研究,下面总结我这几天的理解和认知。

    先阐述下,我在Web项目开发中为什么会用到多线程?项目背景是这样的:门户网站中添加了页面静态化的功能,那对于静态页面内容的更新,采用什么更新策略呢?我用的是最简单的方法,启用定时任务,每隔一段指定的时间清空静态页面文件所在的目录(关于这点,如果有更好做法或建议的,请指点一哈),在项目开始运行时,就启用定时任务开始工作。显然,启用定时任务,可以简化认为开始一个新的线程,来专门执行删除静态页面文件的操作。

    为了实现上述的功能,不需要我们从最原始的多线程编程方式入手,通过网上的搜索,大致有三种解决方案。如下:

  • 使用Quartz开源任务调度框架。

  • 使用JDK Timer类。

  • 使用Spring“原生态”的Spring Task。

    针对前两种方法,Spring都给予了完美的封装和整合。那么关于Quartz和JDK Timer是什么,做什么,怎么用,可以自己搜索下,这里不作重点描述。但需要强调的是,这么多的方法,哪个是适用的。

    一、多种任务调度方案的对比

  • Quartz:复杂,重量级,功能强大;可以实现定时、定点的任务调度;提供了调度运行环境的持久化机制;提供组件式的侦听器、各种插件、线程池等功能。

  • JDK Timer:可以完成简单的定时任务调度;只适合执行时间非常短的任务调度;由于Timer中所有的任务在单一的背景线程中运行,经常会出现时间漂移、任务挤压等问题。

  • Spring任务调度:可以看作是轻量级的“Quartz”,可以实现定时、定点的任务调度功能;是Spring自带的功能,使用简单方便。

    综合上述内容,由于要解决的问题很简单,就选用了Spring任务调度。当然,如果需要更为复杂的任务调度功能时,还是要选用Quartz的。至于JDK Timer,局限太多,不作考虑了。选定了解决方案后,谈一下我在学习和了解过程的一些感悟。

    二、理解任务、异步、多线程

    我在调研Quartz、JDK Timer和Spring任务调度的过程中,见到最多的关键词是任务、调度、异步、线程等。可能有人会疑惑,本文开头我强调的是多线程,可说到这儿用到的却是任务调度,这两个概念有何关联?我谈下我的理解,不一定对,欢迎指正。

    我在看相关资料时,包括Spring文档中,相提并论是任务调度和异步执行。我认为:

  • 任务的重点在于调度。

  • 异步(操作)的重点在于并发。

  • 一个异步操作也可以当作一个任务,但可能并不涉及调度。

    上述两点的实现依靠多线程的技术。而其中Quartz以及Spring的封装、优化中都提到了线程池技术,我认为线程池是多线程编程,或者准确地说并发操作的一种优化措施。

    三、认知TaskExceutor和TaskScheduler

    在学习Spring文档中任务调度的相关部分时,接触到了TaskExecutor和TaskScheduler。这里我只简单描述一下自己的理解,因为自己感觉理解的不是很透彻,所以这点还望高人看到后能给予补充纠正。

    JDK5.0新增了一个并发工具包java.util.concurrent,其中执行器Executor是其中一个重要的类。Executor的存在是为了方便处理并发操作,它对Runnable实例的执行进行了抽象,使实现者可以提供更为丰富的实现。JDK5.0提供的实现者大多拥有线程池的内在支持,Spring为Executor处理引入了新的抽象层,继而诞生了TaskEexcutor和TaskScheduler。

    不过值得注意的是,TaskExecutor的实现也提供了很多线程池的支持,可见利用线程池来处理数量巨大的短小并发任务是有很大好处的,具体可以了解下Java线程池的意义。但TaskExecutor并不全是使用线程池的,具体使用场景可以查看Spring文档中关于TaskExecutor的实现。

    我所认为的是,TaskExecutor的作用是绑定Runnable实例,可以决定是否实现异步操作,类似我们使用过的new Thread(Runnable run)。而TaskScheduler更多的则是为了绑定异步操作时,同时设定调度规则。但谈到这里,我抛出一个疑惑,非异步操作的任务是否存在调度的意义?个人感觉关于TaskScheduler的实现应用较多还是ThreadPoolTaskScheduler,主要是对异步任务的调度处理。下面来具体谈一下使用Spring对任务调度的实现吧。

    四、Spring任务调度功能的理解

    有种较好的理解,应用程序执行的与用户行为无关的操作成为后台任务。而Spring对后台任务分为了两种,并提供了封装与实现,如下:

  • 调度任务

  • 异步方法

    Spring同样提供了xml配置和注解两种方式来实现后台任务的功能。

    http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/scheduling.html中描述的很详细,这里我不再做过多说明。重点强调我对一些关键点的理解。

  • 无论是注解还是xml配置,在用到了task命名空间,需要在Spring的配置文件中声明task的命名空间。

  

<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>


  • 如上代码所示,使用注解方式,需要在Spring配置文件中添加<task:annotation-driven />。<task:executor .../>

    会创建一个ThreadPoolTaskExecutor实例,负责处理标注了@Async注解的异步任务。<task:scheduler .../>会创建一个ThreadPoolTaskScheduler,负责管理调度标注了@Scheduled的方法。可见这样的配置都采用了线程池的技术。如果没有设置pool-size属性,线程池中默认只保持一个线程。

   @Scheduled注解可以对指定方法进行调度,配合fixedDelay、fixedRate和cron属性,可以制定详细的调度规则。

  @Async注解可以指定方法,在被调用时,以异步的方式执行。

    


转载于:https://my.oschina.net/angerbaby/blog/297146

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值