Java执行定时任务(Timer、Quartz)

来源:互联网 发布:python wxpython 教程 编辑:程序博客网 时间:2024/05/29 19:37

最近用到定时任务,这里总结一下java中常用的几种定时方法。
Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。 Spring和QuartZ都支持cron,功能都很强大,Spring的优点是稍微简单一点,QuartZ的优点是没有Spring也可使用;

一、Timer

这里我们看一下例子:

package test;import java.util.Date;import java.util.Timer;import java.util.TimerTask;/** * 一个实现TimerTask的类(执行具体任务) * @author cye * */public class TimerTest extends TimerTask {    private Timer timer;    public static void main(String[] args) {        TimerTest timerTest = new TimerTest();        timerTest.timer = new Timer();        // 立刻开始执行timerTest任务,只执行一次        // timerTest.timer.schedule(timerTest, new Date());        // 立刻开始执行timerTest任务,执行完本次任务后,隔2秒再执行一次        // timerTest.timer.schedule(timerTest,new Date(),2000);        // 一秒钟后开始执行timerTest任务,只执行一次        // timerTest.timer.schedule(timerTest,1000);        // 一秒钟后开始执行timerTest任务,执行完本次任务后,隔2秒再执行一次        // timerTest.timer.schedule(timerTest,1000,2000);        // 立刻开始执行timerTest任务,每隔2秒执行一次        timerTest.timer.scheduleAtFixedRate(timerTest, new Date(), 2000);        // 一秒钟后开始执行timerTest任务,每隔2秒执行一次        // timerTest.timer.scheduleAtFixedRate(timerTest,1000,2000);        try {            Thread.sleep(10000);        } catch (InterruptedException e) {            e.printStackTrace();        }        // 结束任务执行,程序终止        timerTest.timer.cancel();        // 结束任务执行,程序并不终止,因为线程是JVM级别的        // timerTest.cancel();    }    @Override    public void run() {        System.out.println("Task is running!");    }}

二、Quartz

Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。Quartz 允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。整合了 Quartz 的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业。虽然可以通过属性文件(在属性文件中可以指定 JDBC 事务的数据源、全局作业和/或触发器侦听器、插件、线程池,以及更多)配置 Quartz,但它根本没有与应用程序服务器的上下文或引用集成在一起。结果就是作业不能访问 Web 服务器的内部函数;例如,在使用 WebSphere 应用服务器时,由 Quartz 调度的作业并不能影响服务器的动态缓存和数据源。

作业和触发器

Quartz 调度包的两个基本单元是作业和触发器。
调度器:调度器用于将与作业触发器关联,一个作业可关联多个触发器,这样每个触发器被可以触发的作业执行;一个触发器可用于控制多个作业,触发触发时,全部作业将获得调度。Quartz的调度器由Scheduler接口体现。
作业 是能够调度的可执行任务,触发器 提供了对作业的调度(有SimpleTrigger和CronTrigger两种类型)。虽然这两个实体很容易合在一起,但在 Quartz 中将它们分离开来是有原因的,而且也很有益处。通过把要执行的工作与它的调度分开,Quartz 允许在不丢失作业本身或作业的上下文的情况下,修改调度触发器。而且,任何单个的作业都可以有多个触发器与其关联。

  1. 作业: 首先创建一个实现了org.quartz.Job接口的类,并实现这个接口的唯一一个方法execute(JobExecutionContext arg0) throws JobExecutionException
package com.crystal.springmvc.timer;import java.text.SimpleDateFormat;import java.util.Date;import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;/** * @author cye */public class SimpleQuartzJob implements Job {    /**     * @param context:作业实例的运行时上下文,它提供了对调度器和触发器的访问,这两者协作来启动作业以及作业的 JobDetail 对象的执行。     *  Quartz 通过把作业的状态放在 JobDetail 对象中并让 JobDetail 构造函数启动一个作业的实例,分离了作业的执行和作业周围的状态。     *  JobDetail 对象储存作业的侦听器、群组、数据映射、描述以及作业的其他属性。     */    @Override    public void execute(JobExecutionContext context) throws JobExecutionException {        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");        System.out.println("In SimpleQuartzJob - executing its JOB at " + sdf.format(new Date()) + " by " + context.getTrigger());    }}

2.Cron 触发器
CronTrigger 基于 cron 表达式,支持类似日历的重复间隔

package com.crystal.springmvc.timer;import java.text.SimpleDateFormat;import java.util.Date;import org.quartz.CronScheduleBuilder;import org.quartz.CronTrigger;import org.quartz.JobBuilder;import org.quartz.JobDetail;import org.quartz.Scheduler;import org.quartz.SchedulerException;import org.quartz.SchedulerFactory;import org.quartz.TriggerBuilder;import org.quartz.impl.StdSchedulerFactory;public class SimpleTriggerRunner {    public void task() throws SchedulerException {        //实例化一个 SchedulerFactory,获得此调度器        SchedulerFactory schedulerFactory = new StdSchedulerFactory();        Scheduler scheduler = schedulerFactory.getScheduler();        // 初始化job任务        JobDetail jobDetail = JobBuilder.newJob(SimpleQuartzJob.class)                .withIdentity("jobDetail-s1", "jobDetailGroup-s1").build();        // 初始化触发器 CronTrigger        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("simpleTrigger", "triggerGroup-s1")                .startAt(new Date()).withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")).build();        Date ft = scheduler.scheduleJob(jobDetail, trigger); // 注册并进行调度        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");        System.out.println(jobDetail.getKey() + " 已被安排执行于: " + sdf.format(ft)                + ",并且以如下重复规则重复执行: " + trigger.getCronExpression());        scheduler.start();  // 开始执行,start()方法被调用后,计时器就开始工作,计时调度中允许放入N个Job        try { // 主线程等待一分钟            Thread.sleep(60L * 1000L);        } catch (Exception e) {        }        scheduler.shutdown(true);   // 关闭定时调度,定时器不再工作    }}

Cron 表达式包括以下 7 个字段:
格式: [秒] [分] [小时] [日] [月] [周] [年]

序号 说明 是否必填 允许填写的值 允许的通配符 1 秒 是 0-59 , - * / 2 分 是 0-59 , - * / 3 小时 是 0-23 , - * / 4 日 是 1-31 , - * ? / L W 5 月 是 1-12 or JAN-DEC , - * / 6 周 是 1-7 or SUN-SAT , - * ? / L # 7 年 否 empty 或 1970-2099 , - * /

通配符说明:
* 表示所有值. 例如:在分的字段上设置 “*”,表示每一分钟都会触发。
? 表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为”?” 具体设置为 0 0 0 10 * ?
- 表示区间。例如 在小时上设置 “10-12”,表示 10,11,12点都会触发。
* , 表示指定多个值,例如在周字段上设置 “MON,WED,FRI” 表示周一,周三和周五触发
/ 用于递增触发。如在秒上面设置”5/15” 表示从5秒开始,每增15秒触发(5,20,35,50)。在月字段上设置’1/3’所示每月1号开始,每隔三天触发一次。
L 表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六,相当于”7”或”SAT”。如果在”L”前加上数字,则表示该数据的最后一个。例如在周字段上设置”6L”这样的格式,则表示“本月最后一个星期五”
W 表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上设置”15W”,表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 “1W”,它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,”W”前只能设置具体的数字,不允许区间”-“).
注意: ‘L’和 ‘W’可以一组合使用。如果在日字段上设置”LW”,则表示在本月的最后一个工作日触发(一般指发工资 )
# 序号(表示每月的第几个周几),例如在周字段上设置”6#3”表示在每月的第三个周六.注意如果指定”#5”,正好第五周没有周六,则不会触发该配置(用在母亲节和父亲节再合适不过了)
注意:周字段的设置,若使用英文字母是不区分大小写的 MON 与mon相同.

Corn表达式在线验证:http://cron.qqe2.com/

0 0
原创粉丝点击