Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
7.7k views
in Technique[技术] by (71.8m points)

Java Timer schedule疑问

按照接口文档,schedule方法会以特定的延迟执行任务,相当于在前一个任务完成时,再delay一段时间执行下一个任务。

@Test
public void test2() {
    Timer timer = new Timer(true);
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("start");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end");
        }
    }, 0, 5000);
    while (true) {
    }
}

那这个代码,上一次输出start end后,下一个start不应该延迟5s再输出吗?可实际运行,输出end后总是立刻输出了start,感觉不太对啊。


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

因为你task的运行时间超过了timer的周期,核心源码在这:

java.util.TimerThread#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
 // 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) {
 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
 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) {
 } }}

taskFired 的判断条件是 executionTime<=currentTime,你的这种情况是true,接下来任务就直接run了:

if (taskFired) // Task fired; run it, holding no locks
 task.run();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...