一:简单代码实现:
import java.util.Timer;
import java.util.TimerTask;
public class RunTimer {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TestTamerTask(),0,1200);
timer.scheduleAtFixedRate(new jiayou(), 0, 1200);
}
}
class jiayou extends TimerTask{
@Override
public void run() {
System.out.println("甲由由甲有假");
}
}
二:理论知识:
1. Timer和TimerTask
Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。
TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务。
一些注意的问题
· 每一个Timer仅对应唯一一个线程。
· Timer不保证任务执行的十分精确。
· Timer类的线程安全的。
2.如何终止Timer线程
默认情况下,创建的timer线程会一直执行,主要有下面四种方式来终止timer线程:
· 调用timer的cancle方法
· 把timer线程设置成daemon线程,(new Timer(true)创建daemon 线程),在jvm里,如果所有用户线程结束,那么守护线程也会被终止, 不过这种方法一般不用。
· 当所有任务执行结束后,删除对应timer对象的引用,线程也会被终止。
· 调用System.exit方法终止程序
关于cancle方式终止线程
这种方式终止timer线程,jdk的实现比较巧妙,稍微说一下。
首先看cancle方法的源码:
public void cancel() {
synchronized(queue) {
thread.newTasksMayBeScheduled = false;
queue.clear();
queue.notify(); // In case queuewas already empty.
}
}
没有显式的线程stop方法,而是调用了queue的clear方法和queue的notify方法,clear是个自定义方法,notify是Objec自带的方法,很明显是去唤醒wait方法的。
再看clear方法:
void clear() {
// Null out task references to prevent memory leak
for (int i=1; i<=size; i++)
queue[i] = null;
size = 0;
}
clear方法很简单,就是去清空queue,queue是一个TimerTask的数组,然后把queue的size重置成0,变成empty.还是没有看到显式的停止线程方法,回到最开始new Timer的时候,看看new Timer代码:
public Timer() {
this("Timer-" + serialNumber());
}
public Timer(String name) {
thread.setName(name);
thread.start();
}
看看这个内部变量thread:
private TimerThread thread = new TimerThread(queue);
不是原生的Thread,是自定义的类TimerThread.这个类实现了Thread类,重写了run方法,如下:
public void run() {
try {
mainLoop();
} finally {
// Someonekilled this Thread, behave as if Timer cancelled
synchronized(queue) {
newTasksMayBeScheduled = false;
queue.clear(); // Eliminateobsolete references
}
}
}
最后是这个mainLoop方法,这方法比较长,截取开头一段:
private void mainLoop() {
while (true) {
try {
TimerTask task;
booleantaskFired;
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;
可以看到wait方法,之前的notify就是通知到这个wait,然后clear方法在notify之前做了清空数组的操作,所以会break,线程执行结束,退出。
3.schedule和scheduleAtFixedRate
(1)2个参数的schedule在制定任务计划时, 如果指定的计划执行时间 scheduledExecutionTime<=systemCurrentTime,则task会被立即执行。 scheduledExecutionTime不会因为某一个task的过度执行而改变。
(2)3个参数的schedule在制定反复执行一个task的计划时,每一次执行这个task的计划执行时间随着前一次的实际执行时间而变,也就是scheduledExecutionTime(第n+1次)=realExecutionTime(第n次)+periodTime。也就是说如果第n 次执行task时,由于某种原因这次执行时间过长,执行完后的 systemCurrentTime>=scheduledExecutionTime(第n+1次),则此时不做时隔等待,立即执行第n+1次 task,而接下来的第n+2次task的scheduledExecutionTime(第n+2次)就随着变成了realExecutionTime(第n+1次)+periodTime。说白了,这个方法更注重保持间隔时间的稳定。
(3)3个参数的scheduleAtFixedRate
在制定反复执行一个task的计划时,每一次执行这个task的计划执行时间在最初就被定下来了,也就是
scheduledExecutionTime(第n次)=firstExecuteTime+n*periodTime;如果第n次执行task时,由于某种原因这次执行时间过长,执行完后的systemCurrentTime>=scheduledExecutionTime(第n+1次),则此时不做period间隔等待,立即执行第n+1次task,而接下来的第n+2次的task的scheduledExecutionTime(第n+2
次)依然还是firstExecuteTime+(n+2)*periodTime这在第一次执行task就定下来了。说白了,这个方法更注重保持执行频率的稳定。