Java 计时器计划与 scheduleAtFixedRate?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20844735/
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
Timer schedule vs scheduleAtFixedRate?
提问by M Sach
public class MyTimerTask extends TimerTask{
@Override
public void run() {
int i = 0;
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Run Me ~" + ++i);
System.out.println("Test");
}
}
Case 1 :-
TimerTask task = new MyTimerTask();
Timer timer = new Timer();
timer.schedule(task, 1000,6000); // line 1
System.out.println("End"); // here is bebug point.
My Expectation of schedule()
method (as per my understanding given in javadocs
where each execution is scheduled once previous task execution is completed)
that two threads should be
created after line 1.
我对schedule()
方法的期望(根据我的理解,javadocs
一旦前一个任务执行完成,每个执行被安排在哪里)应该在第 1 行之后创建两个线程。
One for timer
which spawns another thread for tasks. Once first task thread dies
another will be created and son on. But at debug point , i just see one thread corresponding to Timer
. Why
not thread for tasks which implement Runnable
?
一个timer
为任务产生另一个线程。一旦第一个任务线程死亡,另一个将被创建并继续下去。但在调试点,我只看到一个线程对应于Timer
. 为什么不线程执行的任务Runnable
?
Case 2 :-
TimerTask task = new MyTimerTask();
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 1000,6000); // line 1
System.out.println("End"); // here is bebug point.
My Expectation of scheduleAtFixedRate()
method(as per my understanding given in javadocs where each execution is scheduled relative to the scheduled
execution time of the initial execution) that around 17 threads(dont pay much attention
to 17. It can be more or less to that. But it should be greater than 2 ) should be
created after line 1.
我对scheduleAtFixedRate()
方法的期望(根据我在 javadocs 中给出的理解,其中每个执行都是相对于初始执行的计划执行时间安排的)大约 17 个线程(不要太关注 17。它可能或多或少。但是它应该大于 2 ) 应该在第 1 行之后创建。
One for timer
which should spawn 16 other thread corresponding two each task. At first task sleeps
for 100 second, Timer
should create another thread corresponding to next task and similarly for other task.
But at debug point , i just see one thread corresponding to Timer
. Here also i can see sequential execution of task. Why not 17 threads?
其中一个timer
应该产生 16 个其他线程,每个任务对应两个。第一个任务休眠 100 秒,Timer
应该创建另一个线程对应下一个任务,其他任务类似。但在调试点,我只看到一个线程对应于Timer
. 在这里我也可以看到任务的顺序执行。为什么不是 17 个线程?
UPDATE:- As per ScheduleAtFixedRate javadocs, 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. what does that mean?
To me it gives impression, if second task is due even first task is not completed, then timer will create new thread for due task. Is n't it?
更新:- 根据ScheduleAtFixedRate javadocs,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. what does that mean?
对我来说它给人的印象是,如果第二个任务到期,即使第一个任务没有完成,那么计时器将为到期任务创建新线程。不是吗?
采纳答案by Sotirios Delimanolis
The javadoc for Timer
says
Corresponding to each Timer object is a single background thread that is used to execute all of the timer's tasks, sequentially.
对应于每个 Timer 对象的是一个单独的后台线程,用于按顺序执行所有计时器的任务。
Basically it holds a queue of tasks to which it adds when you schedule them. It uses one thread to iterate over the queue and execute the tasks.
基本上它持有一个任务队列,当你安排它们时它会添加到这些任务队列中。它使用一个线程遍历队列并执行任务。
回答by t_ozawa
The timer class creates one thread per instance of the timer class and this thread do all tasks scheduled Timer#schedule or Timer#scheduleAtFixRate.
计时器类为计时器类的每个实例创建一个线程,该线程执行所有计划的 Timer#schedule 或 Timer#scheduleAtFixRate 任务。
So, as you ovserved, the timer creates only one thread.
因此,正如您所观察到的,计时器仅创建一个线程。
A task would have came start time before the preciding task has finished, then the follwing task has waited until the preciding task has finished.
任务将在预测任务完成之前到达开始时间,然后后续任务一直等到预测任务完成。
So, Timer "never" create another thread although the preciding task hasn't finished and the time the following task has to start has come.
因此,尽管预测任务尚未完成并且下一个任务必须开始的时间已经到来,但 Timer “从不”创建另一个线程。
So, I advise you that:
if you want to schedule tasks and do the tasks on time whether a preciding task has finished or not, use ScheduledThreadPoolExecutor instead of Timer.
所以,我建议你:
如果你想安排任务并按时完成任务,无论一个重要的任务是否完成,请使用 ScheduledThreadPoolExecutor 而不是 Timer。
And though if you do not want, it's prefer to use ScheduledThreadPoolExecutor than Timer because for one thing, tasks scheduled by Timer would never have done if a task would have threw RuntimeException or Error.
虽然如果您不想要,它更喜欢使用 ScheduledThreadPoolExecutor 而不是 Timer,因为一方面,如果任务抛出 RuntimeException 或 Error,则 Timer 调度的任务永远不会完成。
回答by Matt Klein
Timer
uses the Active Objectpattern under the hood, so there is only ever a single thread being used and scheduling a new task on the timer adds that task to the thread's tasks queue.
Timer
在幕后使用活动对象模式,因此只有一个线程正在使用,并且在计时器上调度新任务会将该任务添加到线程的任务队列中。
The timer thread keeps track of all the tasks in it's queue and sleeps until the next task is scheduled. Then, it wakes up and executes the task itself by invoking task.run()
directly, meaning that it does not spawn another thread to execute the code.
计时器线程跟踪其队列中的所有任务并休眠,直到安排下一个任务。然后,它通过task.run()
直接调用唤醒并执行任务本身,这意味着它不会产生另一个线程来执行代码。
This also means that if you schedule two tasks to execute at the same time then, true to the Active Object pattern, they will be executed sequentially (one after another) on the same thread of control. This means the second task will execute after it's scheduled time (but probably not by much).
这也意味着,如果您安排两个任务同时执行,则符合主动对象模式,它们将在同一控制线程上按顺序(一个接一个)执行。这意味着第二个任务将在预定时间之后执行(但可能不会太多)。
Now, to unequivocally answer your question, here is the scheduling logic from Timer.class
that schedules the next time that the task should be run again (from lines 262-272 here):
现在,为了明确回答您的问题,这里是调度逻辑,该调度逻辑Timer.class
会在下次再次运行任务时进行调度(来自此处的第 262-272 行):
// set when the next task should be launched
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);
task.fixedRate
is set to true if you use one of the timer.scheduleAtFixedRate()
methods and is set to false if you use one of the timer.schedule()
methods.
task.fixedRate
如果使用其中一种timer.scheduleAtFixedRate()
方法,则设置为 true,如果使用其中一种方法,则设置为 false timer.schedule()
。
task.when
is the "time" (ticks) that the task was scheduled to run.
task.when
是任务计划运行的“时间”(滴答声)。
task.period
is the interval you passed to the timer.schedule*()
method.
task.period
是您传递给timer.schedule*()
方法的间隔。
So, from the code we can see that if you use a fixed rate then a repeating task will be scheduled to run relative to when it was first started. If you don't use a fixed rate, then it is scheduled to run relative to when it was last run (which will drift relative to a fixed rate, unless your task is never delayed and takes less than one tick to execute).
因此,从代码中我们可以看到,如果您使用固定速率,那么将安排重复任务相对于首次启动时运行。如果您不使用固定速率,那么它会被安排相对于上次运行的时间运行(这将相对于固定速率漂移,除非您的任务从不延迟并且执行时间少于 1 个刻度)。
This also means that if a task falls behind and it is on a fixed rate, then Timer
will keep rescheduling the task for immediate execution until it catches up to the total number of times it should have ran over a given period.
这也意味着如果一个任务落后并且它的速率是固定的,那么Timer
它将继续重新调度任务以立即执行,直到它赶上它应该在给定时间段内运行的总次数。
So if you have a task, say a ping()
that you schedule to run at a fixed rate every 10ms and there is temporary blocking in the ping()
method to where it takes 20ms to execute, then the Timer
will call ping()
again immediately after the previous call finished, and it will keep doing so until the given rate is achieved.
所以,如果你有一个任务,说ping()
您计划以固定速度每10ms运行,并有暂堵在ping()
方法到需要20ms的执行,那么Timer
将调用ping()
再次紧接在上通话结束后,它将继续这样做,直到达到给定的速率。
回答by Sanchelz
Schedule will not execute the missed task if the start time is in the past. scheduleAtFixedRate will execute the missed tasks if the start time is in the past.For the missed tasks, the start time will be calculated based last task's end time. When missed tasks are executed fully, the new normal tasks' start time will be calculated based on last task's start time.
如果开始时间在过去,Schedule 将不会执行错过的任务。如果开始时间在过去,scheduleAtFixedRate 将执行错过的任务。对于错过的任务,将根据最后一个任务的结束时间计算开始时间。当错过的任务全部执行完后,新的普通任务的开始时间将根据上一个任务的开始时间计算。
BR Sanchez
BR桑切斯