Jan*_*rek 24 java java-8 java-time
默认的java.time.Clock实现基于System.currentTimeMillis().正如这里所讨论的那样, 单调增加Java的时间?,不保证是单调的.
事实上,我经常遇到一种情况,系统时间会自动调整到过去几秒钟,而java时钟也会跳回来.
//now() returns 2016-01-13T22:34:05.681Z
order.setCreationTime(Instant.now());
//... something happens, order gets cancelled
//now() returns 2016-01-13T22:34:03.123Z
//which is a few seconds before the former one,
//even though the call was performed later - in any reasonable sense.
//The recorded history of events is obviously inconsistent with the real world.
order.setCancelationTime(Instant.now());
Run Code Online (Sandbox Code Playgroud)
然后,当人们不能仅依靠一个方向的时间时,就不可能执行时间敏感的事情,例如记录和分析事件历史.
上述帖子说System.nanoTime()是单调的(如果底层系统支持它).所以,如果我想将我的代码基于java.time API,我需要内部使用nanoTime的Clock来确保单向流动的时间.也许这样的事情会起作用.或者不是吗?
public class MyClock() extends java.time.Clock {
private final long adjustment;
public MyClock() {
long cpuTimeMillis = System.nanoTime()/1000000;
long systemTimeMillis = System.currentTimeMillis();
adjustment = systemTimeMillis - cpuTimeMillis;
}
@Override
public long millis() {
long currentCpuTimeMillis = System.nanoTime()/1000000;
return currentCpuTimeMillis + adjustment;
}
}
Run Code Online (Sandbox Code Playgroud)
它只是一个草图,而不是一个完整的时钟实现.我想一个正确的实现也应该对构造函数中传递的另一个Clock执行调整,而不是直接针对currentTimeMillis().
或者,在任何地方都可以使用这种单调时钟实现吗?我猜想一定有很多人面临同样的问题.
感谢鼓舞人心的评论和答案.评论中有几个有趣的点,所以我将在这里总结一下.
1.单调时钟
至于我原来的问题,是的,有可能让单调时钟不受系统时间的影响而向后跳.如上所述,这种实现可以基于System.nanoTime().过去曾经存在过这种方法的问题,但它应该在今天的现代系统上运行良好.这种方法已经在例如Time4J库中实现,它们的单调时钟可以很容易地转换为java.time.Clock:
Clock clock = TemporalType.CLOCK.from(SystemClock.MONOTONIC);
Run Code Online (Sandbox Code Playgroud)
2.适当的系统时间控制
它可以配置系统时间管理(unix/linux中的ntpd),这样系统时间几乎不会向后移动(如果需要,它会慢下来),然后可以依赖系统时间单调,没有时钟 - Java中需要魔法.
我会这样做,因为我的应用程序是服务器端,我可以控制时间.实际上,我经历了我自己安装的实验环境中的异常(只有表面的肤浅知识),并且它只使用ntpdate客户端(如果时间不同步,它可以向后跳转),而不是ntpd(其中可以配置,以便它不会跳回).
3.使用序列而不是时钟
当需要跟踪之前发生的强烈关系时,从原子生成的序列中提供事件序列号并且不依赖于挂钟更安全.一旦应用程序在多个节点上运行,它就成为唯一的选择(虽然这不是我的情况).