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);