1. 具体实例
继承TimerTask抽象类
实现两个子类TimerJob和TimerJob2
package com.husky.timer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
/**
* @author husky
* @date 2018/9/17 9:41
*/
public class TimerJob extends TimerTask {
@Override
public void run() {
System.out.println("当前执行的任务是TimerJob");
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current time : "+sf.format(date));
System.out.println("当前线程: "+Thread.currentThread().getName());
}
}
package com.husky.timer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
/**
* @author husky
* @date 2018/9/17 10:40
*/
public class TimerJob2 extends TimerTask {
@Override
public void run() {
System.out.println("当前执行的任务是TimerJob2");
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current time : "+sf.format(date));
System.out.println("当前线程: "+Thread.currentThread().getName());
}
}
测试类
public class TimerRun {
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current time:"+sf.format(date));
System.out.println(Thread.currentThread().getName());
System.out.println("开始执行定时任务=======");
Timer timer = new Timer();
TimerJob timerJob = new TimerJob();
TimerJob2 timerJob2 = new TimerJob2();
timer.schedule(timerJob,3000,2000);
timer.schedule(timerJob2,5000,3000);
}
}
/**
运行结果:
Current time:2018-09-18 16:11:08
main
开始执行定时任务=======
当前执行的任务是TimerJob
Current time : 2018-09-18 16:11:11
当前线程: Timer-0
当前执行的任务是TimerJob
Current time : 2018-09-18 16:11:13
当前线程: Timer-0
当前执行的任务是TimerJob2
Current time : 2018-09-18 16:11:13
当前线程: Timer-0
当前执行的任务是TimerJob
Current time : 2018-09-18 16:11:15
当前线程: Timer-0
当前执行的任务是TimerJob2
Current time : 2018-09-18 16:11:16
当前线程: Timer-0
*/
具体源码分析:
首先分析Timer:
-
成员变量
private final TaskQueue queue = new TaskQueue(); //该对象是封装了TimerTask的数组,实现类似于list /**class TaskQueue { private TimerTask[] queue = new TimerTask[128]; private int size = 0; 该对象也可以通过他的add方法,进行数组扩容 */ private final TimerThread thread = new TimerThread(queue); //这个线程是等待timerqueue上的task,执行一次任务,重复执行任务,以及移除一些任务 //这个类很重要,等会具体分析
-
构造函数
public Timer() {
this("Timer-" + serialNumber());
}
public Timer(boolean isDaemon) {
this("Timer-" + serialNumber(), isDaemon);
}
public Timer(String name) {
thread.setName(name);
thread.start();
}
public Timer(String name, boolean isDaemon) {
thread.setName(name);
thread.setDaemon(isDaemon);
thread.start();//从这儿可以看出,启动了TimerThread线程
}
- 重要方法
public void schedule(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, -period);
}
//此处将delay加上当前时间,获取执行时间
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
// Constrain value of period sufficiently to prevent numeric
// overflow while still being effectively infinitely large.
if (Math.abs(period) > (Long.MAX_VALUE >> 1))
period >>= 1;
synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}
queue.add(task);//将TimerTask的子类放入到TimerQueue中
if (queue.getMin() == task)
queue.notify();
}
}
好了,上面实现了添加任务,下面就是执行了,我们来分析TimerThread
- 大致
class TimerThread extends Thread {
boolean newTasksMayBeScheduled = true;
private TaskQueue queue;
TimerThread(TaskQueue queue) {
this.queue = queue;
}
public void run() {
try {
mainLoop();
} finally {
// Someone killed this Thread, behave as if Timer cancelled
//意外杀死了线程,表现的像Timer注销
synchronized(queue) {
newTasksMayBeScheduled = false;
queue.clear(); // Eliminate obsolete references
}
}
}
- 具体分析mainLoop方法
private void mainLoop() {
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized(queue) {
// Wait for queue to become non-empty
while (queue.isEmpty() && newTasksMayBeScheduled)
queue.wait();
if (queue.isEmpty())
break; // Queue is empty and will forever remain; die
//如果一直没有task进入数组,die
// Queue nonempty; look at first evt and do the right thing
long currentTime, executionTime;
task = queue.getMin();
//获取TimerQueue中最前的task,也就是执行时间最近的
synchronized(task.lock) {
if (task.state == TimerTask.CANCELLED) {
queue.removeMin();
continue; // No action required, poll queue again
}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
if (task.period == 0) { // Non-repeating, remove//判断是否要重复执行,不需要直接remove
queue.removeMin();
task.state = TimerTask.EXECUTED;//更改task状态
} else { // Repeating task, reschedule
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);//更改重复执行的task的下一次的运行时间
}
}
}
if (!taskFired) // Task hasn't yet fired; wait//如果还没到执行时间,等待
queue.wait(executionTime - currentTime);
}
if (taskFired) // Task fired; run it, holding no locks
task.run();//task运行
//,这边使用的是run()而不是start(),也就是说run方法是简单的方法,要按照顺序执行,而不是线程的run方法,在这个地方并没有对run方法进行try/catch
} catch(InterruptedException e) {
}
}
}
缺陷分析
Timer是单线程
案例:
有两个重复任务(repeat task),task1正常任务,task2会抛出异常,第一个是先执行的,而第二个后执行的,如果正常执行,执行的顺序
task1 ,task1 ,task2,task1 ,task1,。。。,
当执行到task2时,抛出异常,而我们在运行的时候,在TimerThread的mainLoop中的task.run(),我们并没有进行try catch,也就是说,一旦出现异常,我们没有捕获,timer-0这个线程就会终止,而timer有时单线程,也就是会出现程序异常终止。
因为,自己的底子一般般,博文中的一些术语可能使用错误,或者有字打错,望指正。