我尝试使用ScheduledExecutorService每15分钟调用一次可运行的任务。这些任务应该在以下时间每小时运行一次: 第二分钟第10秒 第17分钟第10秒 第32分钟第10秒 第47分钟第10秒。
我使用Calendar实例计算首次执行任务的初始延迟,然后使用scheduleAtFixedRate()的延迟每15分钟执行一次任务。这在前几天工作正常,但几天之后我可以观察到任务执行的一些时间变化。例如,应该在12:03:45开始调用应该在12:03:45开始的任务。我在哪里错了?
public static void main(String[] args) {
final ScheduledExecutorService scheduler = Executors
.newScheduledThreadPool(15);
Date aDate = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(aDate);
int currentHour = cal.get(Calendar.HOUR_OF_DAY);
int currentMins = cal.get(Calendar.MINUTE);
int currentSecs = cal.get(Calendar.SECOND);
int unitInSecs;
int delayFor15MinTasksInSecs;
unitInSecs = currentMins * 60 + currentSecs;
delayFor15MinTasksInSecs = unitInSecs < (3 * 60 - 50 ) ? (3 * 60 - 50 ) - unitInSecs : unitInSecs < (18 * 60 - 50 ) ? (18 * 60 - 50 ) - unitInSecs : unitInSecs < (33 * 60 - 50 ) ? (33 * 60 - 50 ) - unitInSecs : unitInSecs < (48 * 60 - 50 )? (48 * 60 - 50 ) - unitInSecs : (63 *60 - 50 ) - unitInSecs;
scheduler.scheduleAtFixedRate(new RTPAcquiringTask(10), delayFor15MinTasksInSecs, 15*60, TimeUnit.SECONDS);
}
答案 0 :(得分:4)
答案 1 :(得分:1)
正如correct Answer by Riaz及其评论所说,Oracle’s或OpenJDK项目等传统Java实现不是real-time systems。所以他们没有完美的时间。诸如ScheduledExecutorService
之类的课程并非旨在完美地保持时间。如果需要,请查看制作real-time Java的尝试。
我没有尝试过这种解决方法来减少漂移;只是一个想法。
作为一种解决方法,您可以拥有一个额外的后台线程,其工作是偶尔终止您当前的ScheduledExecutorService
工作,并开始重新计算延迟编号的新工作。你说漂移在几天之后变得明显,所以也许这个终止和重新安排的家务活每天运行一次。
您可以通过捕获ScheduledExecutorService
调用返回的ScheduledFuture
对象来跟踪和终止该scheduleAtFixedRate
工作。目前您的调用忽略并丢失该返回的对象。跟踪它,让它可用于我建议的后台线程。请致电cancel
以终止。