我正在尝试将Java 8中的高数据速率UDP流接口模拟器/测试器写入具有非常精确的时间处理器卡的实时机器。每条消息都有一个时间字段,该字段的分辨率为微秒。该接口依赖于高分辨率时间处理器进行数据包排序。界面依赖于我没有的高精度时间卡,需要模拟等式。我想我可以使用这样的东西逃脱:
TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
它确实可以工作但是在长时间运行后我发现UDP会咬我,因为我发送了几百个无序的数据包并且具有相同的时间戳,而接口的另一端无法告诉我收到的数据包无序。接口在某种程度上容忍了这一点,但这对于具有高精度时钟的真实系统来说并不是真正的问题。
为了缓解这种情况,我在currentTimeMillis()中添加了一个合成微秒感,如下所示:
class TimeFactory {
private long prev;
private long incr;
public long now() {
final long now = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
long synthNow = now;
if(now == prev) {
if(incr < 999) {
incr += 1;
}
synthNow += incr;
} else {
incr = 0;
}
prev = now;
return synthNow;
}
}
有没有人像这样处理合成时间?有没有其他方法来收紧这个代码甚至更好的方法来处理这个(使用nanoTime以某种方式)?如果我发送了超过999个数据包,那么增加到毫秒范围是安全的(即:增量+ 1000或更多)?看起来我在currentTimeMillis()调用之间的差异大约是10-15ms,但我确定这是非常依赖于系统的。
答案 0 :(得分:2)
如果有人对此感兴趣,我最终会解决缺乏高分辨率系统时钟的问题。它会给我一个合成的微秒计数器,它会递增,直到System.currentTimeMillis()返回一个更新的值,或者你调用了999次。在实践中,我只看到最多约500个增量。看起来我不会担心溢出到毫秒范围内。
我仍然愿意接受其他更实际的结果选择。
public class SyntheticMicrosClock extends Clock {
private final ZoneId zone;
private long prev;
private long incr;
SyntheticMicrosClock (ZoneId zone) {
this.zone = zone;
}
@Override
public ZoneId getZone() {
return zone;
}
@Override
public Clock withZone(ZoneId zone) {
if (zone.equals(this.zone)) { // intentional NPE
return this;
}
return new SyntheticMicrosClock(zone);
}
public long micros() {
final long now = TimeUnit.MILLISECONDS.toMicros(millis());
long synthNow = now;
if(now == prev) {
if(incr < 999) {
incr += 1;
}
synthNow += incr;
} else {
incr = 0;
}
prev = now;
return synthNow;
}
@Override
public long millis() {
return System.currentTimeMillis();
}
@Override
public Instant instant() {
return Instant.ofEpochSecond(0, micros());
}
}
要使用它,我将合成时钟注入我需要的地方。例如:
Clock synthClock = Inject or new SynthClock(ZoneOffset.UTC);
Instant.now(synthClock);
答案 1 :(得分:1)
您需要时间戳还是只需要基于时间的高分辨率增加数字?如果是这样,您可以使用System.nanoTime。
早期的JVM&OS&#39;这个电话有问题。但似乎已经解决了(见第一个答案here)。
当然,它有可能在你身上徘徊。不知道你的协议有什么样的灵活性,但应该有办法解决这个问题。
答案 2 :(得分:1)
基于@Bill所建议的,你有200年以上的nanoTime分辨率,所以为什么不在init上存储nanoTime,在init上存储currentTimeMillis,然后将nanoTime和initNanoTime的差异添加到initCurrentTimeMillis以获得增强的,高精度的时间戳?一旦你在100ms左右的时间内检测到这个增强时钟和真实时钟之间的时钟偏差,你就可以重新启动。