Java schedule 和 scheduleAtFixedRate 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22486997/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between schedule and scheduleAtFixedRate?
提问by saplingPro
What is the difference between these 2 methods of Timer
class :
这两Timer
种类的方法有什么区别:
schedule(TimerTask task, long delay, long period)
and
和
scheduleAtFixedRate(TimerTask task, long delay, long period)
Documentationdoesn't make the difference between them clear.
文档并没有使它们之间的区别变得清晰。
采纳答案by JB Nizet
The documentation does explain the difference:
文档确实解释了区别:
schedule:
日程:
In fixed-delay execution, each execution is scheduled relative to the actual execution time of the previous execution. If an execution is delayed for any reason (such as garbage collection or other background activity), subsequent executions will be delayed as well.
在固定延迟执行中,每次执行都相对于前一次执行的实际执行时间进行调度。如果执行因任何原因(例如垃圾收集或其他后台活动)延迟,后续执行也将延迟。
So, suppose the delay is 5 seconds, and each task takes 2 seconds, you would get
所以,假设延迟是 5 秒,每个任务需要 2 秒,你会得到
TTWWWTTWWWTTWWWTT
where T
means 1 second for the task execution, and W
means 1 second waiting.
其中T
表示任务执行时间W
为 1 秒,表示等待时间为 1 秒。
But now suppose that a long GC (represented by a G
) happens and delays the second task, the third one will start 5 seconds after the start of the second one, as if the long GC didn't happen:
但是现在假设一个 long GC(由 a 表示G
)发生并延迟了第二个任务,第三个将在第二个任务开始后 5 秒开始,就好像 long GC 没有发生一样:
TTWWWGGTTWWWTTWWWTT
The third task starts 5 seconds after the second one.
第三个任务在第二个任务后 5 秒开始。
scheduleAtFixedRate:
scheduleAtFixedRate:
In fixed-rate execution, each execution is scheduled relative to the scheduled execution time of the initial execution. If an execution is delayed for any reason (such as garbage collection or other background activity), two or more executions will occur in rapid succession to "catch up.".
在固定速率执行中,每次执行都是相对于初始执行的调度执行时间进行调度的。如果由于任何原因(例如垃圾收集或其他后台活动)导致执行延迟,则将快速连续发生两个或多个执行以“赶上”。
So, with the same delay as above, and the same GC, you would get
因此,使用与上述相同的延迟和相同的 GC,您将得到
TTWWWGGTTWTTWWWTT
The third task task starts 3 seconds instead of 5 after the second one, to catch up.
第三个任务任务在第二个任务之后 3 秒而不是 5 秒开始,以赶上。
回答by Eugene
Thanks @Nizet's answer, I have written a sample code for some people who want to practice and learn.
感谢@Nizet 的回答,我为一些想要练习和学习的人编写了示例代码。
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest {
public static void main(String args[]){
TimerTest.DelayTask task = new DelayTask();
Timer timer = new Timer();
/**
* Use schedule or scheduletAtFixedrate and check the printed result
*/
timer.schedule(task, 0, 5000);
//timer.scheduleAtFixedRate(task, 0, 5000);
}
public static boolean stop = false;
public static void delayOneSec(String status){
try{
System.out.print(status);
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
}
static class DelayTask extends TimerTask{
int count = 2;
@Override
public void run() {
// TODO Auto-generated method stub
stop = true;
for(int i = 0; i < count; i++){
TimerTest.delayOneSec("T");
}
if(count == 2){
count = 6;
}else{
count = 2;
}
stop = false;
new PrintW().start();
}
}
static class PrintW extends Thread{
@Override
public void run(){
while(!stop){
TimerTest.delayOneSec("W");
}
}
}
}
The task itself will repeat to take 2 seconds or 6 seconds. Let's see the result of each scenario.
任务本身将重复执行 2 秒或 6 秒。让我们看看每个场景的结果。
When using timer.schedule(task, 0, 5000);
, the output is TTWWWTTTTTTTTWWWTTTTTTTTWWWTTTTTTTT
. As you can see, the timer follow the rules like below, wait till period
time outs if task finishes in time, launch next task immediately if current task lasts more than period
.
使用时timer.schedule(task, 0, 5000);
,输出为TTWWWTTTTTTTTWWWTTTTTTTTWWWTTTTTTTT
。如您所见,计时器遵循以下规则,period
如果任务及时完成,则等待超时,如果当前任务持续时间超过 ,则立即启动下一个任务period
。
When using timer.scheduleAtFixedRate(task, 0, 5000);
, the output is TTWWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTT
. Things are a little different now. The javadoc
使用时timer.scheduleAtFixedRate(task, 0, 5000);
,输出为TTWWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTT
。现在情况有些不同。文档
two or more executions will occur in rapid succession to "catch up."
两个或多个处决将快速连续发生以“赶上”。
takes effect here. As you can see, ignoring the first TTWWW
, every two tasks will print TTTTTTTTWW
and it lasts 10 seconds(two periods).
在这里生效。如您所见,忽略第一个TTWWW
,每两个任务将打印一次,TTTTTTTTWW
持续 10 秒(两个周期)。
Let's dig into the source code of Timer
.
让我们深入研究Timer
.
public void schedule(TimerTask task, Date firstTime, long period) {
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, firstTime.getTime(), -period);
}
public void scheduleAtFixedRate(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);
}
As you can see, the period
is transferred to negative value in schedule
method. Let's see what's the difference when scheduling it.
如您所见,period
在schedule
方法中被转换为负值。让我们看看调度时有什么不同。
The below code is in the mainloop
of TimerThread
,
下面的代码是在mainloop
的TimerThread
,
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);
}
}
}
It's where magic happens, for schedule
method, the next task execution time is based on the currentTime
which is calculated right before the this task runs. That means, every task's execution time only be related with previous task starts time.
这就是魔法发生的地方,对于schedule
方法,下一个任务执行时间基于在currentTime
此任务运行之前计算的时间。也就是说,每个任务的执行时间只与前一个任务的启动时间有关。