java中的时间同步
在for-loop中,我通过检索和处理车辆信息来控制基于模拟步骤的交通模拟器SUMO。 为了确保我的程序在“实时”模拟(1个模拟步骤= 1秒),我想在处理阶段之后睡眠我的程序,直到下一个时间步骤开始。 为了获得更好的结果,我正在根据最初采用的参考时间戳计算时间戳。
循环看起来像这样:
System.out.println("start of traffic simulation ..."); for (int i = 0; i < stepCount; i++) { System.out.println("step: " + i); // set before timeStamp beforeTimeStamp = System.currentTimeMillis(); if (firstStep) { // get reference timeStamp referenceTimeStamp = beforeTimeStamp; firstStep = false; } else { // get next vehicleVector vehicleVector = masterControl.traCIclient.simulateStep(); } // process vehicleVector // set after timeStamp afterTimeStamp = System.currentTimeMillis(); processingTime = afterTimeStamp - beforeTimeStamp; // calculate sleepTime sleepTime = referenceTimeStamp + ((i + 1) * 1000) - afterTimeStamp; // sleep for sleepTime ms Thread.sleep(sleepTime); } System.out.println("end of traffic simulation ...");
这是一些变量的输出:
步骤:0 beforeTimeStamp 1252317242565 参考时间:1252317242565 处理时间:394 考试时间:1252317243565 afterTimeStamp 1252317242959 睡觉时间:606 步骤1 beforeTimeStamp 1252317242961 处理时间:665 考试时间:1252317244565 afterTimeStamp 1252317243626 睡眠时间:939(预计:1000 - 665 = 335)
如您所见,睡眠时间仅适用于第一个模拟步骤。 我不知道这里可能出现什么问题。 有人有想法吗?
BR,
马库斯
为什么不睡1000 - processingTime
? 这是你能得到正确答案的最接近的答案。
您的解决方案仅适用于第一步,因为它仅适用于第一步。 您假设您将在referenceTime + (step * 1000)
开始处理每个步骤,但您不会考虑开销(线程hibernate,打印,垃圾收集)。 打印出referenceTimeStamp + ((i + 1) * 1000) - beforeTimeStamp
看看我的意思
由于Java没有提供有关线程调度的绝对保证,因此使用标准Java无法在一段时间内睡眠 。 Java受到操作系统分配CPU时间的影响,您的程序将受到无法预测的垃圾收集暂停的影响。
如果确实需要可预测的执行,那么您需要查看Java的实时规范 。 这里很清楚矫枉过正!
您可以在java.util.concurrent
包中使用ScheduledExecutorService
来定期执行任务(通过hibernate一段时间或以特定速率执行)。 用法:
import static java.util.concurrent.* Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(task, 0, 1, TimeUnit.SECONDS)
但这并不准确 (参见JavaDoc):
但请注意,由于网络时间同步协议,时钟漂移或其他因素 ,相对延迟的到期不一定与启用任务的当前日期一致
(强调我的)
从Java 5开始,Java中有一个简单的标准解决方案。
看一下ScheduledExecutorService 。
它看起来像这样:
ScheduledExecutorService service = Executors.newScheduledThreadPool(1); service.scheduleAtFixedRate(new MyCode(), 0, 1, TimeUnit.SECONDS);
MyCode类实现runnable接口,每秒执行一次。
这不是实时保证,但应足以满足您的需求。
正如其他人强调的那样,你应该睡觉1000 – 处理时间。
忽略Java SE不提供实时平台的事实(因此你不会得到精度),我或许会看看Timer类,特别是Timer.scheduleAtFixedRate() ,它将照顾定期安排任务。
你确定输出来自同一个程序吗? 查看内联突出显示的差异,
step: 0 beforeTimeStamp 1252317242565 reference time: 1252317242565 processing time: 394 test time: 1252317243565 afterTimeStamp 1252317242959 sleepTime: 606 #### It didn't sleep this long at all step: 1 beforeTimeStamp 1252317242961 #### This is only 2ms from last afteTimeStamp processing time: 665 test time: 1252317244565 afterTimeStamp 1252317243626 sleepTime: 939 (exspected: 1000 - 665 = 335) #### This is to make up the deficit from last sleep
拳头睡眠中有604(606-2)缺陷。 所以939(335 + 604)是第二次循环的正确睡眠时间。
Java的睡眠不准确,但它离这个远远不够。 我想你要么在调试器中中断程序,要么代码与输出不匹配。