Timer 定时器使用举例
大家都知道Timer 可以用来做定时任务,
使用举例,定时5s执行sendPing()逻辑:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
sendPing();
}
}, 5 * 1000);
Timer 和TimerTask原理分析
Timer
使用规则:timer 可以定时delay一个时间再执行task,也支持周期性的定时来执行task,schedule(TimerTask task, long delay)和scheduleAtFixedRate(TimerTask task, long delay, long period);
如果timer 不再需要使用,需要调用cancel()来释放timer的thread和其他资源,如果不这样,timer占用的资源可能长时间得不到释放;
多线程不需要做同步操作就可以共享一个timer;
原理:
Timer 中有TimerImpl对象,TimerImpl继承自Thread,所以每个Timer 中都有一个thread来顺序执行tasks;
Timer timer = new Timer();源码如下,默认isDaemon是false,启动用户线程;在TimerImpl中就有调用start,说明执行task的线程已经开始启动;
public Timer(String name, boolean isDaemon) {
if (name == null) {
throw new NullPointerException("name == null");
}
this.impl = new TimerImpl(name, isDaemon);
this.finalizer = new FinalizerHelper(impl);
}
.....
TimerImpl(String name, boolean isDaemon) {
this.setName(name);
this.setDaemon(isDaemon);
this.start();
}
下面来看看FinalizerHelper这个内部类,
垃圾回收器准备释放内存的时候,会先调用finalize(),那么你可能不知道为什么需要在这里notify线程;
private static final class FinalizerHelper {
private final TimerImpl impl;
.....
@Override protected void finalize() throws Throwable {
try {
synchronized (impl) {
impl.finished = true;
impl.notify();
}
} finally {
super.finalize();
}
}
}
请看TimerImpl 线程的run方法实现:如果不在回收的时候notify,该线程可能会无线循环wait;
public void run() {
while (true) {
TimerTask task;
synchronized (this) {
// need to check cancelled inside the synchronized block
if (tasks.isEmpty()) {
if (finished) {
return;
}
// no tasks scheduled -- sleep until any task appear
try {
this.wait();
} catch (InterruptedException ignored) {
}
continue;
}
long currentTime = System.currentTimeMillis();
task = tasks.minimum();
long timeToSleep;
..........
timeToSleep = task.when - currentTime;
}
//如果需要delay一段时间再执行就先wait
if (timeToSleep > 0) {
// sleep!
try {
this.wait(timeToSleep);
} catch (InterruptedException ignored) {
}
continue;
}
// 如果不需要delay就立即执行
synchronized (task.lock) {
int pos = 0;
if (tasks.minimum().when != task.when) {
pos = tasks.getTask(task);
}
//timertask cancel后从task数组中移除
if (task.cancelled) {
tasks.delete(tasks.getTask(task));
continue;
}
task.setScheduledTime(task.when);//设置执行的时间
// remove task from queue
tasks.delete(pos);
// 根据是否是周期性执行来判断下一次执行的时间
if (task.period >= 0) {
// this is a repeating task,
if (task.fixedRate) {
// task is scheduled at fixed rate
task.when = task.when + task.period;
} else {
// task is scheduled at fixed delay
task.when = System.currentTimeMillis()
+ task.period;
}
// insert this task into queue
insertTask(task);
} else {
task.when = 0;
}
}
}
.......
task.run();
.....
}
- TimerTask
TimerImpl中维护了TimerTask[] timers这个数组,初始大小256;
当调用schedule或者scheduleAtFixedRate,即有需要执行的task时,都会insertTask()到这个数组;如果执行了,就会从数组中delete(),insert时,会notify当前线程,告诉它开始执行task,就是上面的run();
private void insertTask(TimerTask newTask) {
// callers are synchronized
tasks.insert(newTask);
this.notify();
}
TimerTask 实现了Runnable接口,所以定时执行的是task.run();