当计算机在睡眠后醒来时,计划任务会运行数千次



用Spring的@Scheduled注释一个方法并指定一个固定的延迟,比如:

@Scheduled(fixedRate = 5000)
public void test() {
log.info("The time is {}", Instant.now());
}

当我在睡觉后唤醒电脑时,任务会立即运行多次。

The time is 2020-07-14T08:00:30.358073400Z
The time is 2020-07-14T08:00:35.358969600Z
The time is 2020-07-14T08:00:40.358066100Z
...
The time is 2020-07-14T08:02:51.806689500Z
The time is 2020-07-14T08:02:51.806689500Z
The time is 2020-07-14T08:02:51.806689500Z
The time is 2020-07-14T08:02:51.806689500Z
The time is 2020-07-14T08:02:51.806689500Z
The time is 2020-07-14T08:02:51.807651500Z
The time is 2020-07-14T08:02:51.807651500Z
...

如何使它在计算机唤醒时只运行一次?

使用:@Scheduled(cron = "*/5 * * * * *")

当使用cron表达式时,遗漏的执行不会排队。

此外,正如@Lino所注意到的,您指定了fixedRate,而不是fixedDelay。将fixedRate更改为fixedDelay也可以解决您的问题,但请注意,行为可能会发生变化,因为fixedDelay是上一次调用结束和下一次调用开始之间的固定周期(以毫秒计(,而fixedRate是调用之间的固定时段(以毫秒为单位(。

您可以使用AtomicBoolean标志来指示任务已经在运行:

private final AtomicBoolean running = new AtomicBoolean(false);

然后在你计划的方法

if (running.compareAndSet(false, true)) {
log.info("The time is {}", Instant.now());
running.set(false);
}

来自compareAndSet(expect, update):的javadoc

如果当前值==预期值,则原子化地将值设置为给定的更新值。

如果成功,返回trueFalse返回表示实际值与预期值不相等。

因此,if将检查当前是否没有任务正在运行,然后才执行您的代码。

最新更新