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.
我对schedule()
方法的期望(根据我在javadocs
中给出的理解,其中每次执行完成后执行每次执行)
两个线程应该是
在第1行之后创建。
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.
我对scheduleAtFixedRate()
方法的期望(根据我在javadocs中的理解,其中每次执行都是相对于计划安排的
大约17个线程的初始执行的执行时间(不要太注意
这可能或多或少。但它应该大于2)
在第1行之后创建。
一个timer
,它应该产生16个其他线程,每个任务对应两个。在第一个任务睡觉
对于100秒,Timer
应该创建与下一个任务相对应的另一个线程,并且类似于其他任务。
但是在调试点,我只看到一个与Timer
对应的线程。在这里我也可以看到任务的顺序执行。为什么不是17个线程?
更新: - 根据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?
对我来说,它会给人留下印象,如果第二个任务到期,即使第一个任务未完成,那么计时器也会创建新线程适当的任务。不是吗?
答案 0 :(得分:4)
对应每个Timer对象是一个后台线程 用于按顺序执行所有计时器的任务。
基本上,它包含一个任务队列,在您安排它们时会添加这些任务。它使用一个线程迭代队列并执行任务。
答案 1 :(得分:4)
Timer
使用了Active Object模式,因此只有一个线程被使用,并且在计时器上安排新任务会将该任务添加到线程的任务队列中
计时器线程跟踪其队列中的所有任务并休眠,直到安排下一个任务。然后,它通过直接调用task.run()
唤醒并执行任务本身,这意味着它不会产生另一个线程来执行代码。
这也意味着如果你安排两个任务同时执行,那么,对于Active Object模式,它们将在同一个控制线程上顺序执行(一个接一个)。这意味着第二个任务将在其预定时间之后执行(但可能不会太多)。
现在,为了明确回答你的问题,这里是来自Timer.class
的调度逻辑,它安排下次再次运行任务时(来自第262-272行here):
// 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
方法,则 timer.scheduleAtFixedRate()
设置为true;如果您使用timer.schedule()
方法之一,则
task.when
设置为false。
task.period
是"时间" (滴答)任务计划运行。
timer.schedule*()
是您传递给Timer
方法的时间间隔。
因此,从代码中我们可以看到,如果使用固定速率,则重复任务将被安排为相对于首次启动时运行。如果您不使用固定费率,则计划相对于上次运行时运行(相对于固定费率会相对运行,除非您的任务从未延迟并且执行时间不到一个)
这也意味着如果一个任务落后并且它是一个固定的速率,那么ping()
将继续重新安排任务以立即执行,直到它赶上它应该在一个任务上运行的总次数。给定期限。
所以,如果你有一个任务,比如说ping()
你计划以每10ms的固定速率运行,并且在Timer
方法中有临时阻塞,需要20ms执行,然后ping()
将在上一次通话结束后立即再次呼叫{{1}},并且会一直这样做,直到达到给定的费率。
答案 2 :(得分:1)
timer类为每个timer类的实例创建一个线程,这个线程执行所有任务调度Timer#schedule或Timer#scheduleAtFixRate。
因此,当您保留时,计时器只创建一个线程。
任务将在预先安排任务完成之前开始,然后下面的任务一直等到预先安排的任务完成。
所以,虽然预先确定的任务还没有完成,但是“永远不会”创建另一个线程,并且下一个任务必须开始的时间到了。
所以,我告诉你:
如果您想要安排任务并按时完成预先确定的任务是否已完成,请使用ScheduledThreadPoolExecutor而不是Timer。
虽然如果你不想要,它更喜欢使用ScheduledThreadPoolExecutor而不是Timer,因为一方面,如果一个任务抛出RuntimeException或Error,那么Timer调度的任务就永远不会完成。
答案 3 :(得分:0)
如果开始时间是过去,则计划不会执行错过的任务。 scheduleAtFixedRate将在开始时间过去时执行错过的任务。对于错过的任务,将根据上一个任务的结束时间计算开始时间。当完全执行错过的任务时,新的正常任务将被执行。开始时间将根据上一个任务的开始时间计算。
BR桑切斯