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的睡眠不准确,但它离这个远远不够。 我想你要么在调试器中中断程序,要么代码与输出不匹配。