java系统中使用调度器Quartz实现对正在执行任务的停止

4 篇文章 0 订阅

最近在进行数据迁移的任务(就是迁移历史数据),数据量很大,需要运行几个月才能运行完。要求是每天的非工作时间定时进行迁移,正常上班的时间自动停止。自然就想到了使用Quartz来执行定时任务。每天定时的启动任务是没有问题的,Quartz本来就是干这个事情的。但是如何让正在执行的任务定时关闭呢?

通过在网上搜查资料发现了停止执行任务的代码如下:

    public static void removeJob(String jobName, String jobGroupName,
            String triggerName, String triggerGroupName) {
        try {
            SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();
            Scheduler sched = gSchedulerFactory.getScheduler();
            sched.pauseTrigger(triggerName, triggerGroupName);// 停止触发器
            sched.unscheduleJob(triggerName, triggerGroupName);// 移除触发器
            sched.interrupt(jobName, jobGroupName);
            sched.deleteJob(jobName, jobGroupName);// 删除任务
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

但是这个代码是有问题的,因为这样只是把定时任务从调度器中删除了,到下次触发的时刻不会再触发而已,因为调度器中已经没有这个定时任务了嘛。但是并不会把当前正在执行的任务给停止。就拿我的数据迁移来说吧,我每天需要在早上八点把迁移任务停止,每天6点下班之后启动。既然每天还需要触发定时任务,肯定不能把定时任务按照上边的方式删除了。

那现在的问题就是如何才能把迁移任务定时关闭了呢,这就需要我们从我们的迁移程序中去操作了。当当前的时间是8点的时候,我进行一个状态值得修改,根据这个状态值来进行迁移任务的结束。

由于保密原因,下面我只能列出样例代码:

1.操作时间的工具类:

package com.ykp.quartz.test;

import java.util.Calendar;
import java.util.Date;

/**
 * @function:操作时间的工具类
 * @author yankunpeng
 * @date 2015-3-6上午11:45:44
 * @mailto yan095650@163.com
 */
public class DateUtils {

    /**
     * @function:判断当前时间是否在两个时间之间
     * @param currDate
     * @param startDate
     * @param endDate
     * @return boolean
     * @author yankunpeng
     * @date 2015-3-5下午03:56:28
     * @mailto yan095650@163.com
     */
    public static boolean betweenTime(Date currDate, Date startDate,
            Date endDate) {
        boolean b = false;
        try {
            if (currDate.getTime() >= startDate.getTime()
                    && currDate.getTime() <= endDate.getTime()) {
                b = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return b;
    }

    /**
     * @function:获取指定hour小时的前后minute分钟的时间
     * @param hour
     * @param minute
     * @return Date
     * @author yankunpeng
     * @date 2015-3-6上午11:44:49
     * @mailto yan095650@163.com
     */
    public static Date getAfterMinutesDate(int hour, int minute) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, hour); // 控制时
        calendar.set(Calendar.MINUTE, minute); // 控制分
        calendar.set(Calendar.SECOND, 0); // 控制秒
        Date time = calendar.getTime();
        return time;
    }
}

2.调度器工具类:

package com.ykp.quartz.test;

import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;

/**
 * @function:调度器工具类
 * @author yankunpeng
 * @date 2015-3-6下午02:11:50
 * @mailto yan095650@163.com
 */
public class QuartzUtils {
    private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();

    /**
     * @function:添加一个定时任务
     * @param jobName
     * @param jobGroupName
     * @param triggerName
     * @param triggerGroupName
     * @param jobClass
     * @param time
     *            void
     * @author yankunpeng
     * @date 2015-3-6下午02:19:34
     * @mailto yan095650@163.com
     */
    @SuppressWarnings("unchecked")
    public static void addJob(String jobName, String jobGroupName,
            String triggerName, String triggerGroupName, Class jobClass,
            String time) {
        try {
            Scheduler sched = gSchedulerFactory.getScheduler();
            JobDetail jobDetail = new JobDetail(jobName, jobGroupName, jobClass);// 任务名,任务组,任务执行类
            // 触发器
            CronTrigger trigger = new CronTrigger(triggerName, triggerGroupName);// 触发器名,触发器组
            trigger.setCronExpression(time);// 触发器时间设定
            sched.scheduleJob(jobDetail, trigger);
            // 启动
            if (!sched.isShutdown()) {
                sched.start();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

3.调度任务类:

package com.ykp.quartz.test;

import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * @function:调度任务类
 * @author yankunpeng
 * @date 2015-3-6上午11:06:07
 * @mailto yan095650@163.com
 */
public class QuartzJob implements Job {
    public static boolean stop = false;// 停止任务的标志,默认是打开
    private static int stoptime = 14;// 停止的起始时间
    private static int before = 8;// 提前分钟数,可以是所有整数
    private static int delay = 9;// 延迟分钟数,可以是所有整数
    private static Date currDate;// 当前时间
    private static Date startDate;// 开始时间,通过stoptime和before计算出来的
    private static Date endDate;// 结束时间,通过stoptime和delay计算出来的

    static {
        currDate = new Date();
        startDate = DateUtils.getAfterMinutesDate(stoptime, before);
        endDate = DateUtils.getAfterMinutesDate(stoptime, delay);
    }

    @Override
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        try {
            final String jobName = arg0.getJobDetail().getName();

            int i = 0;
            int count = 1000000;// 这个是满足迁移的数据条数,实际应该从数据库中查询的
            while ((!stop) && i < count) {
                int num = 1000;// 每次从数据库查询最前边的1000条,相当于分页查询,但又不是分页查询,因为每次查询时我们的数据是在减少
                for (int j = 0; j < num; j++) {// 实际上这里应该使用while,但是为了演示,所有使用for
                    try {
                        System.out.println("任务:"
                                + jobName
                                + "-->"
                                + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                                        .format(new Date()) + ".........");
                        Thread.sleep(1 * 100);
                        i++;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 判断当前的时间是都在startDate和endDate之间,如果在,则把停止任务的标志位修改成true,这样迁移任务就结束了
                currDate = new Date();
                stop = DateUtils.betweenTime(currDate, startDate, endDate);
                if (stop) {
                    System.out.println("停止迁移任务:" + jobName);
                }
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            stop = false;// 最后记得把标记恢复初始值,等待迁移任务的下次执行
        }
    }
}

4.测试类:

package com.ykp.quartz.test;

/**
 * @function:测试调度器
 * @author yankunpeng
 * @date 2015-3-6下午02:20:18
 * @mailto yan095650@163.com
 */
public class QuartzTest {
    public static void main(String[] args) {
        try {
            String jobName = "动态任务调度";
            String jobGroupName = "任务组名";
            String triggerName = "触发器名";
            String triggerGroupName = "触发器组名";
            String time = "0 07,10 14 * * ?";

            QuartzUtils.addJob(jobName, jobGroupName, triggerName,
                    triggerGroupName, QuartzJob.class, time);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行测试类,运行之前可以设置触发规则:0 07,10 14 * * ?,意思是在14:07和14:10时刻分别触发

    private static int stoptime = 14;// 停止的起始时间
    private static int before = 8;// 提前分钟数,可以是所有整数
    private static int delay = 9;// 延迟分钟数,可以是所有整数

这段代码说明在任务运行到14:08-14:09时间段内,任务就会停止。

注意:为什么停止的时间是一个时间段呢,因为我们每次运行1000条,每次1000条运行完了我们才会进行判断当前时间是否满足了停止的条件,我们没有必要迁移一条数据就去判断,没这个必要。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值