Java计时器和scheduleAtFixedRate + 系统暂停

7

我正在开发一个Java程序,并使用Timer对象来每隔几分钟或几小时运行任务。在正常操作中,这很好用,但是我在Mac的“睡眠模式”中遇到了问题(也许在其他操作系统上也会出现问题,但我还没有尝试过)。

请考虑以下代码示例:

//Setup the timer to fire the ping worker (every 3 minutes)
_PingTimer.scheduleAtFixedRate(new TimerTask(){
        public void run(){
            Program.PingThread = new PingWorker(Settings.Username, Settings.UserHash, true, true);
            Program.PingThread.CheckOpenPort = true;
            Program.SwingExecutor.execute(Program.PingThread);
        }
    }, 0, 180000);

在正常运行中,这个定时器每3分钟会触发一次,足够准确(我不关心具体的秒数或其他什么)。问题在于,睡眠了几个小时后,似乎会向系统发送积压的定时器请求。
它似乎会在睡眠期间运行所有错过的定时器任务,试图弥补失去的时间。
有没有办法可以防止这种情况发生?我尝试使用“synchronized”和其他线程技术,但这只能确保它们不会同时运行。它们仍然会一个接一个地运行,直到处理完积压任务为止。
感谢您提供的任何帮助!

“can't help” - 是只有在 Mac 上出现,还是普遍存在于睡眠模式? - AlanFoster
2个回答

5
你看过API了吗?它明确说明了以下内容:
在固定速率执行中,每次执行都是相对于初始执行的预定执行时间进行安排的。如果由于任何原因(例如垃圾收集或其他后台活动)而延迟执行,则会连续发生两个或多个执行以“赶上”进度。从长远来看,执行频率将完全等于指定周期的倒数(假设Object.wait(long)底层的系统时钟是准确的)。
这就是为什么你应该考虑使用ScheduledExecutorService的原因之一。这个链接也可能会有用。

显然我错过了这个重要的提示!感谢你关于ScheduledExecutorService的建议。我正在研究这个,今晚我会进行测试。 - jocull
嗯,我试了试,似乎结果是一样的。不过我刚刚意识到我使用的是scheduleAtFixedRate而不是scheduleWithFixedDelay。我现在再尝试一次用后者。 - jocull
“scheduleWithFixedDelay”是关键!现在一切似乎都井然有序了。再次感谢您! - jocull
1
非常感谢!这个问题在Windows上也会发生。有一段时间我们想知道为什么从休眠中唤醒后CPU使用率会飙升,直到我们意识到scheduleWithFixedDelay会用线程淹没你的CPU。 - Aaron Ong

2

使用schedule而不是scheduleAtFixedRate


“schedule” 自己不会重新排队,对吧? - jocull

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接