Java定时任务的常用实现
Java的定时任务有以下几种常用的实现方式:
1)Timer
2)ScheduledThreadPoolExecutor
3)Spring中集成Cron Quartz
接下来依次介绍这几类具体实现的方式
1. Timer
利用Java自带的定时类java.util.Timer以及java.util.TimerTask共同实现多任务的定时触发与周期性执行,主要包含以下两个方法:
void schedule(TimerTask task, long delay, long period);
void scheduleAtFixedRate(TimerTask task, long delay, long period);
其中delay表示第一次执行的延迟(毫秒),period表示周期性执行的时间间隔(毫秒)。其中,需要特别注意的是这两个方法中的period都为该任务后一次执行的起始时间与前一次执行的起始时间只差,但schedule()方法该任务后一次执行的起始时间并非固定,而是取决于前一次任务的执行耗时(如果该耗时大于period,那后一次执行必须等待前一次执行完毕后立即执行,所以并不是严格的时间间隔);反观scheduleAtFixedRate()方法后一次执行则不受前一次执行耗时的影响,因此如果前一次执行较慢,可能出现两次执行并发执行的场景。
Timer典型的用法如下:
long delay = 1000L;
long period = 5000L;
Timer timer = new Timer();
timer.schedule(new TimerTask(){
@Override
public void run() {
// TODO Auto-generated method stub
}
}, delay, period);
Timer的实现过程需要依赖内部的任务队列TaskQueue与任务线程TimerThread,其中TaskQueue以最小堆的方式实现任务优先队列,而TimerThread为单线程执行线程。因此存在的一个问题就是一旦该单线程在执行某个任务时由于某些原因hang住,那后续的其余任务执行都会受到影响。
2. ScheduledThreadPoolExecutor
继承自ThreadPoolExecutor的java.util.concurrent.ScheduledThreadPoolExecutor也可以实现多任务的定时触发与周期性执行,并且通常是多线程执行(线程池的形式),主要包含以下两个方法:
ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
其中,scheduleAtFixedRate()方法与Timer的schedule()方法是类似的,后一次执行受到前一次执行耗时的影响;但scheduleWithFixedDelay()方法中的period则表示该任务后一次执行的起始时间与前一次执行的结束时间只差,这点与Timer的scheduleAtFixedRate()方法不同。
既然ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,那构成线程池核心的要素仍然是一样的:
- int corePoolSize
- int maximumPoolSize
- long keepAliveTime
- BlockingQueue<Runnable> workQueue
- ThreadFactory threadFactory
- RejectedExecutionHandler handler
但有所不同的是,ScheduledThreadPoolExecutor允许自定义的参数仅包括corePoolSize、threadFactory和handler,而maximumPoolSize恒为Integer.MAX_VALUE,keepAliveTime恒为0,workQueue恒为new DelayedWorkQueue(),这就意味着工作队列其实是无界的,且maximumPoolSize是无用的,corePoolSize就是工作线程的总个数(不会再增加)。
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
由于ScheduledThreadPoolExecutor是多个线程组成的线程池,因此不容易出现由于某个耗时任务导致其余定时任务难以分配线程无法执行的情况,因此更建议使用ScheduledThreadPoolExecutor取代Timer。
3. Cron Quartz
如果是一个Spring项目,则不妨使用Cron Quartz来更为灵活地制定定时任务,首先需要在pom.xml中增加对其的依赖配置,如下:
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
随后,编写一个XML配置文件(如time-task.xml),用于指定定时任务类和相应的触发时间等(配置的方法不止一种,但本质上大同小异,这里仅提供一种作为参考):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- 后台流量统计定时任务配置 -->
<bean id="flowDaemon" class="com.xxx.stats.service.impl.GetFlowDaemon">
</bean>
<bean id="FlowDaemonDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!--false表示等上一个任务执行完后再开启新的任务 -->
<property name="concurrent" value="false"/>
<property name="targetObject" ref="flowDaemon"/>
<property name="targetMethod" value="execute"/>
</bean> <!-- 调度触发器 -->
<bean id="FlowDaemonTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="FlowDaemonDetail"/>
<property name="cronExpression" value="0 30 0/1 * * ?"/>
</bean> <!-- 调度工厂 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="FlowDaemonTrigger"/>
</list>
</property>
</bean>
</beans>
这里假设定时任务为一个后台流量统计任务,每小时30分触发一次(配置在cronExpression中),执行的方法为com.xxx.stats.service.impl.GetFlowDaemon.execute(),且如果前一个任务延后,后一个任务也顺延(即不会并发执行)。这种配置的好处就在于所有的配置全部在XML文件中完成,而无需对Java代码有任何的改动。
类似于0 30 0/1 * * ?的定时任务时间的设定写法是非常丰富的,支持多样化的需求,详见Cron Quartz官方教程。
REFERENCES
[1] https://my.oschina.net/pingpangkuangmo/blog/745704
[2] http://www.cnblogs.com/hanganglin/articles/3526240.html
[3] http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html
[4] https://my.oschina.net/u/2851681/blog/744997
[5] http://www.cnblogs.com/obullxl/archive/2011/07/10/spring-quartz-cron-integration.html
为尊重原创成果,如需转载烦请注明本文出处:http://www.cnblogs.com/fernandolee24/p/5877516.html,特此感谢
Java定时任务的常用实现的更多相关文章
- atititt.java定时任务框架选型Spring Quartz 注解总结
atititt.java定时任务框架选型Spring Quartz 总结 1. .Spring Quartz (ati recomm) 1 2. Spring Quartz具体配置 2 2.1. 增 ...
- [转][JAVA]定时任务之-Quartz使用篇
[BAT][JAVA]定时任务之-Quartz使用篇 定时任务之-Quartz使用篇 Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与 ...
- Quartz实现JAVA定时任务的动态配置
什么是动态配置定时任务? 首先说下这次主题,动态配置.没接触过定时任务的同学可以先看下此篇:JAVA定时任务实现的几种方式 定时任务实现方式千人千种,不过基础的无外乎 1.JDK 的Timer类 2. ...
- 基于java平台的常用资源整理
这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...
- 这里整理了基于java平台的常用资源
这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...
- Java获取各种常用时间方法大全
Java获取各种常用时间方法大全 package cc.javaweb.test; Java中文网,Java获取各种时间大全 import java.text.DateFormat; import j ...
- java定时任务
java定时任务实现方法: public class TimingTask { private static int count = 0; private static SpiderService s ...
- Java定时任务器
java定时任务,每天定时执行任务.以下是这个例子的全部代码. public class TimerManager { //时间间隔 private static final long PERIOD_ ...
- java中最常用jar包的用途说明
java中最常用jar包的用途说明,适合初学者 jar包 用途 axis.jar SOAP引擎包 commons-discovery-0.2.jar 用来发现.查找和实现可插入式接口,提供一些一般类实 ...
随机推荐
- 前端框架 EasyUI (0) 重新温习(序言)
几年前,参与过一个项目.那算是一个小型的信息管理系统,BS 结构的,前端用的是基于 jQuery 的 EasyUI 框架. 我进 Team 的时候,项目已经进入开发阶段半个多月了.听说整个项目的框架是 ...
- Security Policy:行级安全(Row-Level Security)
行级安全RLS(Row-Level Security)是在数据行级别上控制用户的访问,控制用户只能访问数据库表的特定数据行.断言是逻辑表达式,在SQL Server 2016中,RLS是基于安全断言( ...
- SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论
异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#signalR 后台创建了一个DntHub的集线器 前台在调用的时候出现了问题(经检查是代理对象 ...
- C#多线程之线程池篇2
在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...
- C# 数组的交集、差集、并集
C# 数组的交集.差集.并集 工作中经常会用这方面的知识来检查那些字段是必须输入的,那些是禁止输入. using System; using System.Collections.Generic; u ...
- arcgis api for js入门开发系列五地图态势标绘(含源代码)
上一篇实现了demo的地图查询功能,本篇新增地图态势标绘模块,截图如下: 本篇核心的在于调用API的Draw工具:https://developers.arcgis.com/javascript/3/ ...
- SuperMap-iServer-单点登录功能验证(CAS)
SuperMap-iServer-单点登录功能验证(CAS) 1.测试目的: 验证SuperMap-iServer使用CAS单点登录的功能是否正常. 2.测试环境: SuperMap-iServer8 ...
- 在VMware上安装CentOS -7
1.下载好VMware 2.准备好CentOS的镜像文件 3.打开VMware创建新的虚拟机 选择自定义高级后按下一步 继续下一步 选择稍后安装操作系统 客户机操作系统选择Linux,版本选择Cent ...
- 博客已经迁移至 http://barretlee.com/entry/,时而同步分享到这里
博客园是一个十分好的写作平台,不过个人比较喜欢倒腾,所以将文章都做了搬迁. 博客已经迁移至 http://barretlee.com/entry/,感谢一直以来的关注和支持. 博客订阅地址: http ...
- Hbase学习笔记01
最近做项目接触到了HDFS.mapreduce以及Hbase,有了实战机会,今天打算将这些知识好好总结下,以备不时之需.首先从Hbase开始吧. Hbase是建立在HDFS上的分布式数据库,下图是Hb ...