Java 计时器计划与scheduleAtFixedRate?
我对Java 计时器计划与scheduleAtFixedRate?,java,multithreading,timer,timertask,Java,Multithreading,Timer,Timertask,我对schedule()方法的期望(根据我在javadocs中给出的理解,每次执行都是在前一个任务执行完成后安排的) 那两条线应该是 在第1行之后创建 一个用于计时器,它为任务生成另一个线程。一旦第一个任务线程死亡 另一个将被创建并继续。但在调试点,我只看到一个线程对应于计时器。为什么? 对于实现可运行的任务,不执行线程 public class MyTimerTask extends TimerTask{ @Override public void run() {
schedule()
方法的期望(根据我在javadocs
中给出的理解,每次执行都是在前一个任务执行完成后安排的)
那两条线应该是
在第1行之后创建
一个用于计时器
,它为任务生成另一个线程。一旦第一个任务线程死亡
另一个将被创建并继续。但在调试点,我只看到一个线程对应于计时器。为什么?
对于实现可运行
的任务,不执行线程
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.
我对scheduleAtFixedRate()
方法的期望(根据我在javadocs中给出的理解,其中每个执行都是相对于计划的
初始执行的执行时间)大约17个线程(不太注意
到17。它可以是多多少少。但它应该大于2)应该是
在第1行之后创建
一个用于计时器
,它应该会产生16个其他线程,每个任务对应两个线程。第一个任务是睡觉
对于100秒,Timer
应该创建与下一个任务对应的另一个线程,对于其他任务也是如此。
但在调试点,我只看到一个线程对应于计时器。在这里,我还可以看到任务的顺序执行。为什么不是17条线
更新:-根据,每个执行都是相对于初始执行的计划执行时间安排的。如果执行因任何原因(如垃圾收集或其他后台活动)而延迟,则两个或多个执行将快速连续发生“追上来。这意味着什么?
给我的印象是,如果第二个任务到期,即使第一个任务还没有完成,计时器也会为到期的任务创建新线程。是吗?报纸上说
与每个计时器对象对应的是一个后台线程
用于按顺序执行计时器的所有任务
基本上,它包含一个任务队列,当您安排任务时,它会将任务添加到该队列中。它使用一个线程在队列上迭代并执行任务。timer类为timer类的每个实例创建一个线程,该线程执行所有任务调度timer#schedule或timer#scheduleAtFixRate。
因此,当您启动时,计时器只创建一个线程
一个任务可能在沉淀任务完成之前到达开始时间,然后后续任务一直等到沉淀任务完成
因此,计时器“从不”创建另一个线程,尽管精确任务尚未完成,并且下一个任务必须开始的时间已经到来
因此,我建议您:
如果您想安排任务并按时完成任务,无论是否已完成任务,请使用ScheduledThreadPoolExecutor而不是Timer
尽管您不想这样做,但还是更愿意使用ScheduledThreadPoolExecutor而不是Timer,因为首先,如果任务抛出RuntimeException或Error,Timer调度的任务将永远不会完成。Timer
使用隐藏模式,因此,只有一个线程被使用,在计时器上调度一个新任务会将该任务添加到线程的任务队列中
计时器线程跟踪其队列中的所有任务并休眠,直到安排下一个任务。然后,它通过直接调用task.run()
来唤醒并执行任务本身,这意味着它不会产生另一个线程来执行代码
这也意味着,如果您计划两个任务同时执行,那么,按照活动对象模式,它们将在同一个控制线程上顺序执行(一个接一个)。这意味着第二个任务将在计划时间之后执行(但可能不会太多)
现在,为了明确地回答您的问题,这里是来自Timer.class
的调度逻辑,它调度任务下次应该再次运行的时间(来自第262-272行):
如果使用timer.scheduleAtFixedRate()
方法之一,则将task.fixedRate
设置为true;如果使用timer.schedule()
方法之一,则将其设置为false
task.when
是任务计划运行的“时间”(滴答声)
task.period
是传递给timer.schedule*()
方法的时间间隔
因此,从代码中我们可以看到,如果使用固定速率,则重复任务将被安排相对于其首次启动时运行。如果您不使用固定速率,则计划相对于上次运行的时间运行(这将相对于固定速率漂移,除非您的任务从未延迟且执行时间少于一个刻度)
这也意味着,如果任务落后并且处于固定速率,则计时器将继续重新安排任务以立即执行,直到它赶上在给定时间段内应运行的总次数
因此,如果您有一个任务,比如一个ping()
,您计划以固定速率每10毫秒运行一次,并且ping()
方法中有临时阻塞,需要20毫秒才能执行,那么计时器将在上一次调用完成后立即再次调用ping()
,并且它将一直这样做,直到达到给定的速率。如果开始时间是过去的,则Schedule不会执行错过的任务。
如果开始时间在过去,scheduleAtFixedRate将执行错过的任务。对于错过的任务,将根据最后一个任务的结束时间计算开始时间。当错过的任务完全执行时,新的正常任务的开始时间将根据上一个任务的开始时间计算
BR Sanchez那么,日程安排FixedRate和schedule有什么区别呢?根据我的例子,它们的行为应该相似吗?@MSach在javadoc中<代码>时间表
为固定延迟,而时间表为固定延迟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.
// 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);