最近项目中要用到 调度(定时)任务,发送周报,月报,季报,年报的功能,我把我实现的流程 记下来,一方面 下次方便直接使用,;二 给 一些朋友 一点启发;
本来 一开始 打算使用 平台里已经封装好的调度功能,但是 测试之后 发现不是很好,故打算自己 写一个,首先我想到的是 java里面自带的 调度功能,Timer 于是自己就 测试了一番.
实现步骤如下:
第一: 把你的任务类 taskClass extends TimerTask ,代码如下
public class TestTimer extends TimerTask{
@Override
public void run() {
// 业务执行代码
System.out.println("Timer is running........");
}
}
ps: 比较好奇的我 顺便看了下 TimerTask 的代码 ,下面贴一下
/*** Eclipse Class Decompiler plugin, copyright (c) 2012 Chao Chen (cnfree2000@hotmail.com) ***/
package java.util;
public abstract class TimerTask implements Runnable {
final Object lock = new Object();
int state = 0;
static final int VIRGIN = 0;
static final int SCHEDULED = 1;
static final int EXECUTED = 2;
static final int CANCELLED = 3;
long nextExecutionTime;
long period = 0L;
public abstract void run();
public boolean cancel() {
synchronized (this.lock) {
int i = (this.state == 1) ? 1 : 0;
this.state = 3;
return i;
}
}
public long scheduledExecutionTime() {
synchronized (this.lock) {
return ((this.period < 0L) ? this.nextExecutionTime + this.period
: this.nextExecutionTime - this.period);
}
}
}
看代码 我们可以知道,TimerTask 实现了 Runnable,所以 可以 一个
TestTimer--> TimerTask 开启了一个线程即单线程,TimerTask 为
abstract class 保留抽象(业务)方法run(),添加 辅助 方法 方便管理,run( ) 子类 实现,业务 放于此内.
ps: 多线程 很重要啊!
第二: 启动 Timer
//设置执行时间
Calendar calendar = Calendar.getInstance();
// 每天 14 点 10 分 0秒
calendar.set(Calendar.HOUR_OF_DAY, 14);// 23
calendar.set(Calendar.MINUTE, 10);//50
calendar.set(Calendar.SECOND, 00);
Date date = calendar.getTime();
2.2 获取 Timer 实例
Timer timer = new Timer(true);
2.3 几个重要的 调度 schedule 方法
timer.schedule(task, time);
// time为Date类型:在指定时间执行一次。
timer.schedule(task, firstTime, period);
// firstTime为Date类型,period为long
// 从firstTime时刻开始,每隔period毫秒执行一次。
timer.schedule(task, delay)
// delay 为long类型:从现在起过delay毫秒执行一次
timer.schedule(task, delay, period)
// delay为long,period为long:从现在起过delay毫秒以后,每隔period
// 毫秒执行一次。
timer.scheduleAtFixedRate(task,date.period)
//尽量维持 你设置的节奏
eg1:timer.scheduleAtFixedRate(new TestTimer (), date, period);
ps:date 为第一次 执行时间,以后 每隔 period 时间段 再执行一次
总结优缺点
优点:简单方便 实现过程很简单,只需 extends TimerTask ,reover run() 方法 即可
缺点:
2.单线程 现场容易挂起,我们通过 观看源码 可知 他是 单线程的 ,那么在 执行的过程中 如实出现 未处理的异常,则会直接 挂起,以后不会再执行了
3.限制多 修改 系统时间 有时会导致 现场不再执行,或 sleep 一段时间后 再执行,源码 如下
class TimerThread extends Thread {
boolean newTasksMayBeScheduled = true;
private TaskQueue queue;
TimerThread(TaskQueue paramTaskQueue) {
this.queue = paramTaskQueue;
}
public void run() {
try {
mainLoop();
synchronized (this.queue) {
this.newTasksMayBeScheduled = false;
this.queue.clear();
}
} finally {
synchronized (this.queue) {
this.newTasksMayBeScheduled = false;
this.queue.clear();
}
}
}
mainLoop () 中:
l1 = System.currentTimeMillis();
l2 = localTimerTask.nextExecutionTime;
if ((i = (l2 <= l1) ? 1 : 0) != 0)
if (localTimerTask.period == 0L)
{
this.queue.removeMin();
localTimerTask.state = 2;
}
可知,修改系统时间 会导致 TImer 挂起 或 sleep
往前 修改系统时间 :会直接导致 现场 挂起 -->mainLoop( 取得系统时间 和 下次执行时间 比较 )
往后 修改系统时间: 线程 会继续sleep,并不会 立即执行,一段时间后才会 notify
总之来说 : 缺点较为明显,且不能修改 系统时间