From ec5c10e233980bbe15f43cb50fd587d562c00e5c Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 11 Oct 2025 22:54:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D`CronTimer`=E5=9C=A8=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E9=9D=9E=E5=B8=B8=E5=A4=9A=E6=97=B6=EF=BC=8C=E8=BF=BD?= =?UTF-8?q?=E8=B5=B6=E7=B3=BB=E7=BB=9F=E6=97=B6=E9=97=B4=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E9=81=97=E6=BC=8F=E4=BB=BB=E5=8A=A1=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=88issue#IB49EF@Gitee=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/hutool/v7/cron/CronTimer.java | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/hutool-cron/src/main/java/cn/hutool/v7/cron/CronTimer.java b/hutool-cron/src/main/java/cn/hutool/v7/cron/CronTimer.java index b551770c2..e27c61eb1 100644 --- a/hutool-cron/src/main/java/cn/hutool/v7/cron/CronTimer.java +++ b/hutool-cron/src/main/java/cn/hutool/v7/cron/CronTimer.java @@ -55,32 +55,38 @@ public class CronTimer extends Thread implements Serializable { @Override public void run() { final long timerUnit = this.scheduler.config.matchSecond ? TIMER_UNIT_SECOND : TIMER_UNIT_MINUTE; + final long doubleTimeUnit = 2 * timerUnit; long thisTime = System.currentTimeMillis(); - long nextTime; - long sleep; while(!isStop){ + spawnLauncher(thisTime); + //下一时间计算是按照上一个执行点开始时间计算的 //此处除以定时单位是为了清零单位以下部分,例如单位是分则秒和毫秒清零 - nextTime = ((thisTime / timerUnit) + 1) * timerUnit; - sleep = nextTime - System.currentTimeMillis(); - if(isValidSleepMillis(sleep, timerUnit)){ - if (!ThreadUtil.safeSleep(sleep)) { - //等待直到下一个时间点,如果被中断直接退出Timer - break; - } - - //执行点,时间记录为执行开始的时间,而非结束时间 - spawnLauncher(nextTime); - - // issue#3460 采用叠加方式,确保正好是1分钟或1秒,避免sleep晚醒问题 - // 此处无需校验,因为每次循环都是sleep与上触发点的时间差。 - // 当上一次晚醒后,本次会减少sleep时间,保证误差在一个unit内,并不断修正。 - thisTime = nextTime; - } else{ - // 非正常时间重新计算(issue#1224@Github) + long nextTime = ((thisTime / timerUnit) + 1) * timerUnit; + final long sleep = nextTime - System.currentTimeMillis(); + if(sleep < 0){ + // 可能循环执行慢导致时间点跟不上系统时间,追赶系统时间并执行中间差异的时间点(issue#IB49EF@Gitee) thisTime = System.currentTimeMillis(); + while(nextTime <= thisTime){ + // 追赶系统时间并运行执行点 + spawnLauncher(nextTime); + nextTime = ((thisTime / timerUnit) + 1) * timerUnit; + } + continue; + } else if(sleep > doubleTimeUnit){ + // 时间回退,可能用户回拨了时间或自动校准了时间,重新计算(issue#1224@Github) + thisTime = System.currentTimeMillis(); + continue; + } else if (!ThreadUtil.safeSleep(sleep)) { + //等待直到下一个时间点,如果被用户中断直接退出Timer + break; } + + // issue#3460 采用叠加方式,确保正好是1分钟或1秒,避免sleep晚醒问题 + // 此处无需校验,因为每次循环都是sleep与上触发点的时间差。 + // 当上一次晚醒后,本次会减少sleep时间,保证误差在一个unit内,并不断修正。 + thisTime = nextTime; } log.debug("Hutool-cron timer stopped."); }