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

说到任务调度,大家可能会想到Quartz框架,但是jdk自带的简单任务调度工具类,反而了解的人并不是很多。我觉得如果你的业务相对简单的话,没必要非得用Quartz等框架,使用Timer完全可以胜任的。简单来分享一下我了解的Timer。

  Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。

  TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务。

我是用TimerTask来创建一个任务,其中run方法里是任务调度的逻辑。使用一个Timer对象来调度任务。

首先给一个特别简单的示例:

package com.tgb.ccl.schema;

import java.util.Date;
import java.util.TimerTask;

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

	@Override
	public void run() {
		Date d = new Date();
		for(int i=0;i<3;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;

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

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

	public TaskManager() {
		Timer timer = new Timer();
		FixedTimerTask task = new FixedTimerTask();
		System.out.println("start");

		//0表示立即执行一次,以后每隔一段时间执行一次
		timer.schedule(task, 0, PERIOD);

		//1000表示1秒后执行一次,以后每隔一段时间执行一次
		//timer.schedule(task, 1000, PERIOD);

		//0表示立即执行一次,以后每隔一段时间执行一次
		//timer.schedule(task, 1000, PERIOD);

		// 在当天14点4分整,执行一次,以后不再执行
		//timer.schedule(task, bookTime(15,0,0));

		//在当天14点4分整,执行一次,以后每隔一段时间执行一次
		//如果时间超过了设定时间,会立即执行一次
//		timer.schedule(task, bookTime(0,34,10),PERIOD);
//		timer.scheduleAtFixedRate(task, bookTime(0,40,0),PERIOD);

	}

	private 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;
	}

	public static void main(String[] args) {
		 new TaskManager();
	}
}

只要执行main方法就可以测试了。

大家可能已经注意到了,timer的schedule方法是重载的。参数主要有必须有一个TimerTask实例。第二个参数如果是long类型的,这个参数则是表示延迟时间,以毫秒为单位。如果为1000,那就是1秒后执行任务调度。如果是Date类型,则表示设定任务开始执行的时刻。当时间到达这个时刻,那么任务会自动开始调度。当然如果当前时间已经超过了设定的开始时间,那么会立即执行一次。第三个参数则是可选参数,是long类型的参数,表示调度的间隔时间。如果有这个参数,表示任务是重复性的调度。否则只会执行一次。这个参数依旧以毫秒为单位。

如果你稍微注意一下,就会发现timer不只提供了schedule方法,还提供了scheduleAtFixedRate方法。这两个方法都是任务调度方法,他们有什么区别呢?

区别在于当当前时间已经超过了设定执行时间,schedule方法会立即执行,第二次执行则是按当前执行时间+间隔时间来算的(当然任务执行时间超过了间隔时间,则在第一次执行完毕后,立马会执行第二次)。而scheduleAtFixedRate方法,同样是立即执行一次,但是它第二次执行则是按照(当前执行时间-设定的时间)/时间间隔来计算从设定时间到现在还需要执行多少次。

举个例子:任务调度需要执行2s,间隔时间是10s,我设定的是8点执行。当前时间为8点0分10秒,如果是schedule方法,则会立即执行一次,第二次执行时间则是08:00:20。如果是scheduleAtFixedRate方法,则会立即执行一次,然后计算08:00:10-08:00:00整好还可以执行一次,所以会在08:00:12时,会立即再执行一次,第三次执行则是在08:00:20时执行,以后每隔10s执行一次。

 
 

(左图是schedule方法的测试效果,右图是scheduleAtFixedRate方法的测试效果)

这个跟网上很多人说的不太一样。不过这个是我测试出来了。他们说的那种结果反正我是测不出来。具体你相信哪种,你自己试过就清楚了。

下篇分享一下怎样动态修改Timer的调度计划,敬请期待。

时间: 2024-08-10 02:11:43

任务调度(一)——jdk自带的Timer的相关文章

任务调度(二)——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

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

死锁排查的小窍门 --使用jdk自带管理工具jstack

本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作. 开发时间久了,难免会写出一些一些死锁的代码,自己明明调用该方法可该方法就是不执行.不进该方法.日志也不打印! 这里我们模拟一段死锁的代码,使用jdk自带的管理工具来排查是不是死锁了! 1 //思索代码 2 public class DeadLockDemo implements Runnable{ 3 4 public int flag = 1; 5 //静态对象是类的所有对象共享的 6 privat

使用 jdk自带ssl包 进行 https通讯双向认证

package com.iraid.test; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.URL; import java.security.Key

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自带的工具将中文转换为ascii码

有时候在MyEclipse中,文件只能保存为“ISO-8859-1”的类型,而这种类型的文件时无法保存中文数据的,那么我们只能将中文数据经过Unicode编码才能往文件中保存,这里可以使用JDK自带的工具——native2ascii. 使用命令行窗口,输入“native2ascii”,如下图所示: 输完回车后,光标会另起一行,这时候就可以输入中文了,按回车结束,对应的Unicode码会在下一行显示:

JDK自带XML和 java对象相互转换

下面使用的是JDK自带的类,没有引用任何第三方jar包. Unmarshaller 类使客户端应用程序能够将 XML 数据转换为 Java 内容对象树. 备注:marshal(序列化.排列.整理) Marshaller 类使客户端应用程序能够将 Java 内容树转换回 XML 数据. package hb.jaxb;   import javax.xml.bind.annotation.XmlRootElement;   //1.需要转换的model对象一定要添加@XmlRootElement注

Java 常用的日志工具——JDK自带的java.util.logging包、APACHE 的log4j 与 slf4j日志处理接口

考虑以下情况: (1).根据程序输出可以很好地帮助程序员调试程序.在编写小型程序时,可以在程序中不断增加 System.out.print() 语句来查看程序运行状态:在大型系统中,显然这一做法非常不对,可以考虑将调试信息通过日志处理工具,输出到一个文本文件中,然后查看文件内容. (2).在系统开始线上运行后,系统管理人员需要获知系统的运行情况,包括但不限于系统开始运行时间.系统关闭时间.系统目前处理任务等,这些状态需要输出到一个经过格式化的日志文件中,供管理人员查看: (3).在编写系统,甚至

jdk自带常用命令行工具使用

下面是笔者整理的jdk自带的常用命令行工具的使用方法,全部原创,转载请注明出处,并贴上链接,谢谢! jps命令使用 jstat命令使用 jinfo命令使用 jmap命令使用 jhat命令使用 jstack命令使用 jcmd命令使用