首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring Quartz执行时间

Spring Quartz执行时间
EN

Stack Overflow用户
提问于 2017-10-23 20:16:55
回答 1查看 562关注 0票数 0

我用下面的表达式设置了一个spring quertz计时器:

@Scheduled(cron = "${quartz.expire.data.cron:0 0 0 * * ?}")

但从我们的日志中可以看出,它稍微提前了一点:

2017-10-22 23:59:59.899 scheduler-4

为什么?

EN

回答 1

Stack Overflow用户

发布于 2017-10-23 20:57:32

这可能来自对下一次执行时间的计算。

ReschedulingRunnableschedule方法中,时间取自nextExecutionTime的第68行。在第72行计算执行之前的实际延迟。

代码语言:javascript
复制
66  public ScheduledFuture<?> schedule() {
67      synchronized (this.triggerContextMonitor) {
68          this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext);
69          if (this.scheduledExecutionTime == null) {
70              return null;
71          }
72          long initialDelay = this.scheduledExecutionTime.getTime() - System.currentTimeMillis();
73          this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
74          return this;
75      }
76  }

现在让我们看看CronTriggernextExecutionTime方法中发生了什么

代码语言:javascript
复制
72  @Override
73  public Date nextExecutionTime(TriggerContext triggerContext) {
74      Date date = triggerContext.lastCompletionTime();
75      if (date != null) {
76          Date scheduled = triggerContext.lastScheduledExecutionTime();
77          if (scheduled != null && date.before(scheduled)) {
78              // Previous task apparently executed too early...
79              // Let's simply use the last calculated execution time then,
80              // in order to prevent accidental re-fires in the same second.
81              date = scheduled;
82          }
83      }
84      else {
85          date = new Date();
86      }
87      return this.sequenceGenerator.next(date);
88  }

在第86行,时间被占用。所用的时刻是计算cron定义的下一次执行时间的基础,该时间发生在sequenceGenerator.next

代码语言:javascript
复制
134     Calendar calendar = new GregorianCalendar();
135     calendar.setTimeZone(this.timeZone);
136     calendar.setTime(date);
137
138     // First, just reset the milliseconds and try to calculate from there...
139     calendar.set(Calendar.MILLISECOND, 0);
140     long originalTimestamp = calendar.getTimeInMillis();
141     doNext(calendar, calendar.get(Calendar.YEAR));
142
143     if (calendar.getTimeInMillis() == originalTimestamp) {
144         // We arrived at the original timestamp - round up to the next whole second and try again...
145         calendar.add(Calendar.SECOND, 1);
146         doNext(calendar, calendar.get(Calendar.YEAR));
147     }
148
149     return calendar.getTime();

这肯定需要几毫秒的时间,这在initialDelay中是不存在的。

证明

下面是一个小测试来证明这一点。我创建了一个常规的CronTrigger和一个被操纵的CronTrigger

代码语言:javascript
复制
@Test
public void test() {
    CronTrigger normalTrigger= new CronTrigger("0 0 0 * * ?");
    Date d2 = normalTrigger.nextExecutionTime(new SimpleTriggerContext());
    long initialDelay2 = d2.getTime() - System.currentTimeMillis();
    System.out.println("Normal trigger:"+ initialDelay2);

    //create a manipulated trigger, which takes longer to return the nextExecutionTime
    CronTrigger manipulated = new CronTrigger("0 0 0 * * ?") {
        @Override
        public Date nextExecutionTime(TriggerContext triggerContext) {
            Date nextExecutionTime = super.nextExecutionTime(triggerContext);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
              //ignore
            }
            return nextExecutionTime;
        }
    };
    Date d = manipulated.nextExecutionTime(new SimpleTriggerContext());
    long initialDelay = d.getTime() - System.currentTimeMillis();
    System.out.println("Manipulated trigger:" +initialDelay);
}

从结果中,您可以看到,被操纵的触发器将比未被操纵的触发器提前5秒触发,因为返回nextExecutionTime的时间比未操纵的多5秒。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46889159

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档