我有一个Java应用程序,用于通过UART连接(RS422)与嵌入式设备通信。主机每5毫秒查询微控制器获取数据。以前,我一直使用ScheduledExecutorService scheduleAtFixedRate来调用我的通信协议方法,但这种方法对于所需的精度非常不可靠(正如其他帖子所述)。从微控制器返回的数据中包括一个时间戳(以微秒为单位),使我可以独立于JVM验证接收到的数据包之间的间隔。需要指出的是,当使用scheduleAtFixedRate时,间隔变化非常大,数据包之间的间隔最多可达30毫秒。此外,调度程序还会尝试通过在一毫秒内多次调用Runnable来弥补错过的周期(这对任何人都不意外)。
经过一些搜索,似乎有共识认为JVM不能保证任何形式的精确调度。然而,我决定自己做一些实验,得出了以下结论:
Runnable commTask = () -> {
// volatile boolean controlled from the GUI
while(deviceConnection) {
// retrieve start time
startTime = System.nanoTime();
// time since commProtocol was last called
timeDiff = startTime - previousTime;
// if at least 5 milliseconds has passed
if(timeDiff >= 5000000) {
// handle communication
commProtocol();
// store the start time for comparison
previousTime = startTime;
}
}
};
// commTask is started as follows
service = Executors.newSingleThreadScheduledExecutor();
service.schedule(commTask, 0, TimeUnit.MILLISECONDS);
这个结果非常出色。相邻的时间戳与预期的5毫秒间隔之间的差异从未超过0.1毫秒。尽管如此,这种技术似乎不太对劲,但我还没有想出其他有效的方法。我的问题基本上是,这种方法是否可行,如果不行,应该怎么做?(我正在运行带有JDK 8_74的Windows 10)