先看个小测试程序:
package test;
import java.util.Timer;
import java.util.TimerTask;
public class TestTimer extends TimerTask{
    int number;
    /**
     * @param args
     */
    public static void main(String[] args) {
        Timer timer=new Timer();
        timer.schedule(new TestTimer(), 1000, 1000);
        
    }
    public void run() {
       System.out.println("number="+(++number));
        
    }
}
正常情况该程序每秒打印当前的 number值。
现在我们来改变这个正常情况:
1)保持程序运行
2)通过系统时间栏把系统时间往前调一天。
过一会儿,你会发现该程序停止输出了?
对,要看到下一个输出,你得等一天了,在这种情况下,你即使现在重新调整到正确系统时间,你仍然得等到下一天才能看到输出。
为什么呢?
下面是JDK中Timer调度的核心代码(在原有注释的基础上加了一些):
 /**
     * The main timer loop.  (See class comment.)
     */
    private void mainLoop() {
        while (true) {
            try {
                //to be scheduled task
                TimerTask task;
                //fired one 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
                    // Queue nonempty; look at first evt and do the right thing
                    long currentTime, executionTime;
                    task = queue.getMin();
                    synchronized(task.lock) {
                        if (task.state == TimerTask.CANCELLED) {
                            //find the first task from the queue.
                            queue.removeMin();
                            continue;  // No action required, poll queue again
                        }
                        //here ,use system current time to determin whether or not fire a task
                        currentTime = System.currentTimeMillis();
                        executionTime = task.nextExecutionTime;
                        //So when we change system time to long ago,this expression will be evaluate to false
                        if (taskFired = (executionTime<=currentTime)) {
                            if (task.period == 0) { // Non-repeating, remove
                                queue.removeMin();
                                task.state = TimerTask.EXECUTED;
                            } else { // Repeating task, reschedule
                                queue.rescheduleMin(
                                  task.period<0 ? currentTime   - task.period
                                                : executionTime + task.period);
                            }
                        }
                    }
                    if (!taskFired) // Task hasn't yet fired; wait
                        queue.wait(executionTime - currentTime);
                }
                if (taskFired)  // Task fired; run it, holding no locks
                    task.run();
            } catch(InterruptedException e) {
            }
        }
    }
那么,我们如何能让Timer调度不依赖这种系统时间呢?
Windows API中GetTickCount()返回系统自启动以来的毫秒数。我们可以用这个来替代System.currentTimeMillis().这样即使改变系统时间
Timer的调度也不会所影响。
改完后再来测试一把
public class TestTimer2 extends com.yovn.labs.util.TimerTask{
    int number;
    /**
     * @param args
     */
    public static void main(String[] args) {
        com.yovn.labs.util.Timer timer=new com.yovn.labs.util.Timer();
        timer.schedule(new TestTimer2(), 1000, 1000);
        
    }
    public void run() {
       System.out.println("number="+(++number));
        
    }
}
这时的输出没有再受系统时间的改变了。
本文代码下载:
source code