如果要执行一些简单的定时器任务,无须做复杂的控制,也无须保存状态,那么可以考虑使用JDK 入门级的定期器Timer来执行重复任务。
一、原理
JDK中,定时器任务的执行需要两个基本的类:
java.util.Timer;
java.util.TimerTask;
要运行一个定时任务,最基本的步骤如下:
1、建立一个要执行的任务TimerTask。
2、创建一个Timer实例,通过Timer提供的schedule()方法,将 TimerTask加入到定时器Timer中,同时设置执行的规则即可。
当程序执行了Timer初始化代码后,Timer定时任务就会按照设置去执行。
Timer中的schedule()方法是有多种重载格式的,以适应不同的情况。该方法的格式如下:
void schedule(TimerTask task, Date time)
安排在指定的时间执行指定的任务。
void schedule(TimerTask task, Date firstTime, long period)
安排指定的任务在指定的时间开始进行重复的固定延迟执行。
void schedule(TimerTask task, long delay)
安排在指定延迟后执行指定的任务。
void schedule(TimerTask task, long delay, long period)
安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
Timer是线程安全的,此类可扩展到大量同时安排的任务(存在数千个都没有问题)。其所有构造方法都启动计时器线程。可以调用cancel() 终止此计时器,丢弃所有当前已安排的任务。purge()从此计时器的任务队列中移除所有已取消的任务。此类不提供实时保证:它使用 Object.wait(long) 方法来安排任务。
TimerTask是一个抽象类,由 Timer 安排为一次执行或重复执行的任务。它有一个抽象方法run()----计时器任务要执行的操作。因此,每个具体的任务类都必须继承TimerTask类,并且重写run()方法。另外它还有两个非抽象的方法:
boolean cancel()
取消此计时器任务。
long scheduledExecutionTime()
返回此任务最近实际执行的安排执行时间。
二、例子
下面用Timer实现一个简单例子:
package stu.timer;
import java.util.Date;
import java.util.TimerTask;
/**
* 重复执行的任务
*
* @author leizhimin,2008-10-9 9:20:20
*/
public class TestTimerTask extends TimerTask {
/**
* 此计时器任务要执行的操作。
*/
public void run() {
Date executeTime = new Date(this.scheduledExecutionTime());
System.out.println("本次任务执行的时间是" + executeTime);
}
}
package stu.timer;
import java.util.Timer;
import java.util.TimerTask;
/**
* 测试JDK Timer的执行
*
* @author leizhimin,2008-10-9 9:24:35
*/
public class TestTimer {
public static void main(String[] args) {
Timer timer = new Timer();
TimerTask task = new TestTimerTask();
timer.schedule(task, 500L, 1000L);
}
}
运行结果:
本次任务执行的时间是Thu Oct 09 09:47:57 CST 2008
本次任务执行的时间是Thu Oct 09 09:47:58 CST 2008
本次任务执行的时间是Thu Oct 09 09:47:59 CST 2008
本次任务执行的时间是Thu Oct 09 09:48:00 CST 2008
本次任务执行的时间是Thu Oct 09 09:48:01 CST 2008
本次任务执行的时间是Thu Oct 09 09:48:02 CST 2008
本次任务执行的时间是Thu Oct 09 09:48:03 CST 2008
本次任务执行的时间是Thu Oct 09 09:48:04 CST 2008
本次任务执行的时间是Thu Oct 09 09:48:05 CST 2008
扩展:
①继承TimerTask,重写run方法
package bamboo.task;
import java.util.TimerTask;
public class TimeTaskTest extends TimerTask{
@Override
publicvoid run() {
System.out.println("hi");
}
}
②通过timer来设置某个时间来调用,或者是相隔多长时间调用
package bamboo.test;
import java.util.Date;
import java.util.Timer;
import bamboo.task.TimeTaskTest;
public class TimeTest {
staticTimeTaskTest test=new TimeTaskTest();
publicstatic void main(String [] args){
Timertimer=new Timer();
//启动和间隔的时间1000毫秒
//timer.schedule(test,0,1000);
//设置什么时候执行
//timer.schedule(test, new Date());
}
}
//
另一种方法
用线程很容易实现的。而且比较灵活。下面是一个示例你看看吧:
public class Test implementsRunnable {
int start = 0;
int end = 0;
public Test(int end) {
new Thread(this).start();
this.end = end;
}
public void run() {
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(start == end)
print();
start++;
}
}
private void print() {
System.out.println("你的任务在"+end+"秒钟后执行了");
}
public static void main(String[] args) {
new Test(3);
}
}
另外Java里也有定时器类Timer也可以的,但它的本质也是线程。
///
写一个批处理就可以了。所谓的批处理就是.bat文件。然后把这个文件添加到系统中的“任务计划”中,定时执行这个bat文件就可以了。至于bat文件里面的内容,那就看你调用什么程序了。下面是一个bat文件调用重启命令的例子:
echo %date%-%time%时开始重启 >D:\重启日志.TXT
shutdown -r -f
echo 在%date%-%time%时重启完毕 >D:\重启日志.TXT
并且这个执行完毕之后,在d盘重启日志文档中写入重启时间和重启完毕的时间。
//
使用此封装可以轻松定时发送邮件、发短信、定制闹钟等。
一共2个类:
com.ab.oa.timer.OpenTask.java(开启定时任务)、
com.ab.oa.timer.TimerTaskProxy.java(定时任务的代理类)
com.ab.oa.timer.MyTask.java(测试Demo)
package com.ab.oa.timer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import com.sinosoft.util.logging.LogFactory;
import com.sinosoft.util.logging.Logger;
/**
* 开启定时任务:可以指定执行多少次,是否一直执行,执行的频率
* 构造方法参数依次为:String beginTime,boolean exeForEver, int exeNum, long period
*
* @author uwaysoft 魏韶颖
* @version 1.0
* @time 2009年4月20日14:07:18
*/
public final class OpenTask {
private static Logger logger = LogFactory.getLogger(OpenTask.class);
private static final Timer timer = new Timer();
private String beginTime;
private boolean exeForEver;
private int exeNum;
private long period;
/**
*
* @param beginTime 任务第一次开始执行时间格式如:2009-09-01 08:30:00
* @param exeForEver 此定时任务是否一直执行,如果为true参数exeNum将忽略
* @param exeNum 任务总共执行多少次数如果=1后参数period可随意
* @param period 每隔多长时间执行一次单位毫秒如:24*60*60*1000就是一天
*/
public OpenTask(String beginTime, boolean exeForEver, int exeNum, longperiod) {
super();
this.beginTime = beginTime;
this.exeForEver = exeForEver;
this.exeNum = exeNum;
this.period = period;
}
/**
* 开启定时任务
* @param subClassName 继承了TimerTask的子类名
*
*/
public void openTimerTask(String subClassName) {
try {
Date date = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss").parse(this.beginTime);
if(exeForEver) {
if(period < 1) {
logger.info("错误的执行周期!周期 = " + period + "毫秒");
return;
}else {
if (date.before(new Date())) {
date = this.addDay(date);
}
TimerTask timerTask = (TimerTask)Class.forName(subClassName).newInstance();
//System.out.println("--period = " +period + "毫秒");
timer.scheduleAtFixedRate(timerTask, date,period);
//区别在于如果超时会补上任务
//timer.schedule(timerTask, date, period);
logger.info("定时任务监控线程已成功启动...执行类型:一直执行!");
}
}else {
if(exeNum < 1) {
logger.info("执行次数<1,定时任务不会执行!");
return;
}else {
// TimerTask timerTask = (TimerTask)Class.forName(subClassName).newInstance();
// if(exeNum == 1) {
// timer.scheduleAtFixedRate(newTimerTaskProxy(subClassName,exeNum,timer), date, period);
// logger.info("定时任务已经成功启动...执行次数1次");
// }else {
// timer.scheduleAtFixedRate(newTimerTaskProxy(subClassName,exeNum,timer), date, period);
// logger.info("定时任务已经成功启动...执行次数" + exeNum + "次");
// }
timer.schedule(newTimerTaskProxy(subClassName,exeNum,timer), date,period);
logger.info("定时任务监控线程已经成功启动...预计执行次数" +exeNum + "次");
}
}
} catch (ParseException e) {
e.printStackTrace();
logger.info("传入的时间格式不正确,定时任务不会执行!");
return;
} catch (InstantiationException e) {
logger.info("不能实例化指定类:" + subClassName);
e.printStackTrace();
} catch (IllegalAccessException e) {
logger.info("不能实例化指定类:" + subClassName);
e.printStackTrace();
} catch (ClassNotFoundException e) {
logger.info("不能实例化指定类:
" + subClassName);
e.printStackTrace();
}
}
// 增加或减少天数
public Date addDay(Date date) {
Date sysDate = new Date();
long t = (sysDate.getTime() - date.getTime())/(3600 * 24 * 1000);
Calendar startDT = Calendar.getInstance();
startDT.setTime(date);
startDT.add(Calendar.DAY_OF_MONTH,(int)t+1);
return startDT.getTime();
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
com.ab.oa.timer.TimerTaskProxy.java如下:
package com.ab.oa.timer;
import java.util.Timer;
import java.util.TimerTask;
import com.sinosoft.util.logging.LogFactory;
import com.sinosoft.util.logging.Logger;
/**
*
* @author uwaysoft 魏韶颖
* 时间:2009年4月20日15:02:58
*/
public class TimerTaskProxy extends TimerTask{
Logger logger = LogFactory.getLogger(TimerTaskProxy.class);
private int count;
private Timer timer;
private int hasExeNum = 0;
private TimerTask timerTask;
/**
* 定时任务代理调用客户写的子类run方法
* @param subClassName 子类名
* @param count 执行多少次
* @param timer 定时器
*/
public TimerTaskProxy(String subClassName, int count,Timer timer) {
super();
this.count = count;
this.timer = timer;
try {
this.timerTask = (TimerTask)Class.forName(subClassName).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void run() {
/**
* 运用了多态条件:继承,重写,父类引用指向子类对象所以调用的是子类的run()
*/
timerTask.run();
hasExeNum ++;
if(count == hasExeNum) {
timer.cancel();
logger.info("定时任务执行完毕,线程成功终止!");
}
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
测试及使用Demo如下:
package com.ab.oa.timer;
import java.util.Random;
import java.util.TimerTask;
/**
* 定时任务的模板例子:
* 要使用定时任务只需要:
* 1.写一个类继承TimerTask,把要做的任务写到run方法里
* 2.按照需求调用不同的构造方法
* 3.方法要求写继承了TimerTask的子类全路径名(包名+类名)
*
* @author uwaysoft weisy 时间:2009年4月20日16:36:14
*/
public class MyTask extends TimerTask {
public void run() {
// TODO: write you task here
System.out.println("----正在执行定时任务编号=" + newRandom().nextInt(10000));
}
public static void main(String[] args) {
//如:从5.1开始每天早上8:30给员工发信息一直发送
//OpenTask openTask = new OpenTask("2009-05-01 08:30:00",true, 10, 24*60*60*1000);
//如:从5.1开始每天早上8:30给员工发信息连续发送一周
OpenTask openTask = new OpenTask("2009-04-21 08:58:00",false, 10, 1000);
//如:5.1早上8:30给员工发信息只发送一次
//OpenTask openTask = new OpenTask("2009-05-01 08:30:00",false, 1, 1000);
//如:从5.1开始每天早上8:30给员工发信息每隔2小时发送一次总共发送5次
//OpenTask openTask = new OpenTask("2009-05-01 08:30:00",false, 1, 2*60*60*1000);
//***************错误的参数*************
//OpenTask openTask = new OpenTask("2009-05-01 08:30:00",false, 0, 2*60*60*1000);
//OpenTask openTask = new OpenTask("2009-05-01 08:30:00",false, 2, -2*60*60*1000);
//************************************
openTask.openTimerTask("com.ab.oa.timer.MyTask");
}
}
///
特定时间执行
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Test{
public static voidmain(String[] args) {
Timer t = newTimer();
Date date = newDate();
date.setHours(8);
//1.特定时间运行,注意,这里不能每天都执行,你要根据实际情况做修改
t.schedule(newMyTask(), date);
date.setHours(12);
t.schedule(newMyTask(), date);
date.setHours(14);
t.schedule(newMyTask(), date);
//2.间隔一定时间段运行一次,这里是每5秒
t.schedule(newMyTask(), date, 5000);
}
}
class MyTask extends TimerTask {
public void run(){
System.out.println("run!");
}
}
///
Timer timer = new Timer();
timer.schedule(new MyTask(), firstTime, 24*60*60*1000L);
timer.schedule(new MyTask(), secondTime,24*60*60*1000L);
timer.schedule(new MyTask(),ThirdTime, 24*60*60*1000L);