如何使用System.nanoTime()对事件进行更精确的排序

时间:2016-05-13 10:50:13

标签: java time

我想在应用程序中发生事件时附加时间戳。假设客户端创建一个Event对象,我想将一个创建时间戳附加到Event对象。我可以使用构造函数中的System.currentTimeMillis()来完成此操作。如果创建的Event对象的速度不超过每毫秒一次,则此方法可以正常工作。在这种情况下,每个Event对象从System.currentTimeMillis()获取不同的值,因此对事件对象进行排序。

但是,如果需要创建一个比每毫秒一个对象快的速率的事件对象,那么我的逻辑会中断。根据对象创建速率,2个或更多事件对象最终具有相同的创建时间戳(因为System.currentTimeMillis在快速连续调用时返回相同的值)

现在如何在这种情况下对Event对象进行排序?我知道System.nanoTime(),但这与epoch无关。

我愿意将Event类中的创建时间戳存储分为2个实例变量 - creationTimeInMS(long)和creationTimeInNS(long)

我不想java.sql.Timestamp支持nano第二精度

无论如何我可以利用System.nanoTime来提供事件对象的排序吗?

注意 - 保证事件的创建速度不会超过1纳秒。因此纳秒精度就足够了

我使用的代码如下

class Event {
private long timestamp

public Event() {
...
timestamp = System.currentTimeMillis()
}

因此,如果多个线程以高于1 /毫秒的速率调用Event构造函数,则两个(或更多)Event对象将获得相同的时间戳。

System.nanoTime()如果被调用的速度不超过每纳秒一次,则应返回唯一编号。但是我不确定如何将此数字与时间戳结合使用。我是否将其添加到时间戳以生成纳秒精度时间?

1 个答案:

答案 0 :(得分:1)

依靠挂钟很难实现这一点,时间会发生碰撞而纳米秒的分辨率在实践中难以实现,快速解决方案是在记住其最后一个值的时间周围添加一个包装器。当然,不会在分布式环境中工作。

static class MonotonicClock{
    private long last;
    public MonotonicClock(){
        last = System.currentTimeMillis();
    }
    public synchronized long getNext(){
      long current = System.currentTimeMillis();
      if(last < current){ // last seen is less than "now"
        last = current;
      }else{
         last++; //collision, overclock the time
      }
      return last;
    }
}

在分布式系统中,事情变得更加复杂。您可能需要查看Lamport timestampsVector Clocks