任务调度(二)——jdk自带的Timer 动态修改任务执行计划

上一篇博文《任务调度(一)——jdk自带的Timer》中,简单介绍了一下Timer,本文将分享一下如何动态修改Timer制定的计划。

先上代码:

package com.tgb.ccl.schema.dynamic;

import java.util.Date;

/**
 * 可动态修改的任务
 *
 * @author arron
 * @date 2015年5月9日 下午1:52:15
 * @version 1.0
 */
public class DynamicTimerTask extends  java.util.TimerTask {

	@Override
	public void run() {
		System.out.println("---------start--------");
		Date d = new Date();
		for(int i=0;i<2;i++){
			try {
				Thread.sleep(1000);
				System.out.println("已执行【"+(i+1)+"】秒钟,at: "+d.toLocaleString());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("本次任务调度结束,at: "+new Date().toLocaleString());
		System.out.println("----------------------------------------------");
	}
}
package com.tgb.ccl.schema.dynamic;

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

/**
 * 任务调度管理器
 *
 * @author arron
 * @date 2015年5月9日 下午1:57:19
 * @version 1.0
 */
public class DynamicTaskManager {
	private static final long PERIOD = 5 * 1000;// 5秒钟

	/**
	 * 单例对象
	 */
	private static DynamicTaskManager taskManager = null;	

	/**
	 * 时间调度对象
	 */
	private static Timer timer = new Timer();

	/**
	 * 任务
	 */
	private static DynamicTimerTask task = null;

	static {
		taskManager = new DynamicTaskManager();
	}

	public static DynamicTaskManager getInstance(){
		if(taskManager==null){
			taskManager = new DynamicTaskManager();
		}
		return taskManager;
	}

	public DynamicTaskManager() {
	}

	@SuppressWarnings("deprecation")
	public void startTask(Date startTime, long period){

		System.out.println("设置启动时间: "+startTime.toLocaleString());
		//如果当前时间超过了设定时间,会立即执行一次
		task = new DynamicTimerTask();
		timer.schedule(task, startTime,period);

	}

	/**
	 * 启动定时器
	 */
	public void start() {
		//启动任务,10点40启动任务
		start(DateUtils.bookTime(10,40,0));
	}

	/**
	 * 启动定时器
	 */
	public void start(long preiod) {
		//启动任务,10点40启动任务
		start(DateUtils.bookTime(10,40,0),preiod);
	}

	/**
	 * 启动定时器
	 */
	public void start(Date startTime) {
		start(startTime,PERIOD);
	}

	/**
	 * 启动定时器
	 */
	public void start(Date startTime,long preiod) {
		startTask(startTime,preiod);
	}

	/**
	 * 重新启动
	 */
	public void restart() {
		clean();
		start();
	}

	/**
	 * 清空timer
	 */
	public void clean() {
		if(task != null){
			task.cancel();
		}
		timer.purge();
	}

	/**
	 * 停止任务
	 */
	public void stop(){
		System.out.println("--------任务正在停止---------");
		clean();
		System.out.println("---------任务已停止----------");
	}

	static class DateUtils{
		/**
		 * 增加或减少天数
		 *
		 * @param date
		 * @param CalendarFlag
		 * 				取值 Calendar.DAY_OF_MONTH, Calendar.HOUR_OF_DAY,
		 * 					   Calendar.MINUTE,Calendar.SECOND,Calendar.MILLISECOND
		 * @param num
		 * @return
		 */
		public static Date addDay(Date date, int CalendarFlag, int num) {
			Calendar startDT = Calendar.getInstance();
			startDT.setTime(date);
			startDT.add(CalendarFlag, num);
			return startDT.getTime();
		}

		/**
		 * 设定时间
		 *
		 * @param hour
		 * @param minute
		 * @param second
		 * @return
		 */
		public static Date bookTime(int hour, int minute, int second) {
			Calendar calendar = Calendar.getInstance();
			calendar.set(Calendar.HOUR_OF_DAY, hour);
			calendar.set(Calendar.MINUTE, minute);
			calendar.set(Calendar.SECOND, second);
			Date date = calendar.getTime();
			return date;
		}
	}

	@SuppressWarnings("deprecation")
	public static void main(String[] args) {
		DynamicTaskManager manager = DynamicTaskManager.getInstance();
		//启动任务,会立即执行一次,2s时执行完毕,5s时第二次执行,7s时第二次执行完毕
		manager.start();

		for(int i=0;i<8;i++){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//8s时,stop原任务,动态更改启动时间
		manager.stop();
		System.out.println("当前时间:"+new Date().toLocaleString());

		System.out.println("修改原计划,5s后重新执行");
		//5s后再启动,即13s时再启动
		manager.start(DateUtils.addDay(new Date(), Calendar.SECOND, 5));
	}
}

运行结果如下:

从结果中,我们可以看到,原先的计划是在14:46:40时开始,第二次是在14:46:45,每次执行2s中,也就是说如果不更改任务计划,那么任务将总会在0s或者5s的时候执行。但是我在main方法中,将原来的任务关闭,然后修改了启动时间,当前时间5s后启动新任务。当前时间为14:46:48,5s后执行了新计划。这就完成了任务的动态修改。

首先说一下,如果关闭任务,stop方法完成了这个功能。要想任务不继续执行,必须将task的状态设置为cancel,然后调用timer的purge方法,将队列里的所有状态为cancel的task移除。这样就算到了执行时间,由于task已经移除,也就不会再执行了。如果使用了timer的cancel()方法,那么会将timer中所有的task全部移除掉。这点要注意一下。

其实在项目中使用时,要比这个还要简单。直接修改startTask()方法,启动时间和间隔都是从数据库中取就ok了。只要想更改计划时,先配置好启动时间和间隔,然后自己写一个restart的方法,调用clean和startTask方法即可。

有人问我Timer和Quartz框架的区别。那我就说一下我的理解。Timer毕竟是jdk自带的简易的任务调度工具类,跟Quartz比肯定是鸟枪与大炮的差距。Quartz的配置规则更加强大,更能满足我们的复杂需求,还允许多线程,这是Timer所比不了的。如果你就需要特别简单的任务调度,那么我觉得完全没有必要用Quartz。杀鸡焉用牛刀?!如果你的业务场景比较复杂,比如要求每个月的第4周的最后一个工作日要执行结算工资,如果最后一天是周六,就会向前提一天,在周五执行。这样的场景用Quartz要比Timer简单吧。

不过具体用什么,还需要看项目。没有什么谁更牛,只有谁更适合。

时间: 2024-10-22 04:15:01

任务调度(二)——jdk自带的Timer 动态修改任务执行计划的相关文章

任务调度(一)——jdk自带的Timer

说到任务调度,大家可能会想到Quartz框架,但是jdk自带的简单任务调度工具类,反而了解的人并不是很多.我觉得如果你的业务相对简单的话,没必要非得用Quartz等框架,使用Timer完全可以胜任的.简单来分享一下我了解的Timer. Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次. TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务. 我是用TimerTask来创

jdk自带的动态代理

package com.stone.dp.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * jdk自带的动态代理:必须实现了某个接口:<br> */ public class JdkProxy implements InvocationHandler { private Object obj; publ

Springboot自带定时任务实现动态配置Cron参数

同学们,我今天分享一下SpringBoot动态配置Cron参数.场景是这样子的:后台管理界面对定时任务进行管理,可动态修改执行时间,然后保存入库,每次任务执行前从库里查询时间,以达到动态修改Cron参数的效果.好,咱们一起来看看是怎么回事. Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行.一般用的较少. ScheduledExecutorServic

JDK自带的二分查找算法和自己写的普通二分查找算法的比较(java二分查找源代码)

一.描述 解析和比较JDK自带的二分查找算法和自己写的普通二分查找算法,使用二进制位无符号右移来代替除2运算,并使用产生随机数的方法产生一定范围的随机数数组,调用Arrays类的sort()静态方法,对int类型数组进行排序. Math.random()的用法:会产生一个[0,1)之间的随机数(注意能取到0,不能取到1),这个随机数的是double类型,要想返回指定范围的随机数如[m,n]之间的整数的公式:(int)(Math.random()*(m-n+1)+m) 二.源代码 <span st

JDK自带的定时任务

import java.util.TimerTask; /** * 实现定时任务 * */ public class MyTimerTask extends TimerTask { @Override public void run() { int num = 0; while (num < 3) { num++; System.out.println(num + " Test..."); try { Thread.sleep(1000); } catch (Interrupte

Java多线程基础(二)定时器类:Timer类和TimerTask类

Java多线程基础(二)定时器类:Timer类和TimerTask类 Timer类和TimerTask类是jdk实现定时器功能的早期方法,jdk1.5以前就支持Timer类和TimerTask类.JDK1.5之后引入了新的机制,将在后续博文中研究. 1 指定时间间隔后执行任务 import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class TraditionalTimerTest {

利用jdk自带的运行监控工具JConsole观察分析Java程序的运行

利用jdk自带的运行监控工具JConsole观察分析Java程序的运行 原文链接 一.JConsole是什么 从Java 5开始 引入了 JConsole.JConsole 是一个内置 Java 性能分析器,可以从命令行或在 GUI shell 中运行.您可以轻松地使用 JConsole(或者,它更高端的 “近亲” VisualVM )来监控 Java 应用程序性能和跟踪 Java 中的代码. 二.如何启动JConsole 如果是从命令行启动,使 JDK 在 PATH 上,运行 jconsole

基于jdk自带httpserver开发的最小完整MVC框架

基于jdk自带httpserver开发的最小完整MVC框架 410kb级的完整MVC:solon(83k) + jdkhttp(27k) + enjoy(227k) + snack3(73k) DEMO启动时间:0.1s solon 是一个插件框架,提供MVC,IOC,AOP,注解,插件机制. jdkhttp 基于jdk8自带com.sun.net.httpserver封装而成,有完整的http功能. snack3 提供json和序列化支持,也足够小. enjoy 很难再找到比它更小的模板引擎了

Android学习路线(二十)运用Fragment构建动态UI

要在Android系统上创建一个动态或者多面板的用户界面,你需要将UI组件以及activity行为封装成模块,让它能够在你的activity中灵活地切换显示与隐藏.你可以使用Fragment类来创建这些模块,它们能够表现得有些像嵌套的activity,它们定义着自己的布局,管理自己的生命周期. 当一个fragment指定了它自己的布局,它可以在activity中和其他的fragment配置为不同的组合,这样就能够为不同的屏幕尺寸来修改你的布局配置(在小屏幕上一次展现一个fragment,而在大屏