硬核的分布式概念,有关时间时钟问题和算法的问题( 二 )


  timeval time;
  int status = gettimeofday(&time NULL);  assert(status != -1 \"bsd error\");  return jlong(time.tv_sec) * 1000  +  jlong(time.tv_usec / 1000);



这些函数调用完全相同的gettimeofday系统调用 。 手册页可以为我们提供更多信息 , 但更重要的是提供一些有价值的说明:手册页 。
NAME
       gettimeofday settimeofday - get / set timeNOTES
       The time returned by gettimeofday() is affected by discontinuous
       jumps in the system time (e.g. if the system administrator manually
       changes the system time).  If you need a monotonically increasing
       clock see clock_gettime(2).


如上所述 , 时间受到系统时间的不连续跳跃的影响 , 这可能是向后的 , 因此时钟不是单调的 。 第三个问题的答案是肯定的 , 这是有道理的:如果我们将当前时间改为一小时 , 我们仍然希望currentTimeMillis返回当前时间 , 即使当前时间的定义已经改变 。 这就是为什么它通常被称为挂钟时间 , 如果我们调整它 , 挂钟也可以及时跳回来 。
当前时间的纳秒nanos
可以采用相同的路径探索研究System.nanoTime() 。 让我们从Javadoc开始 , 它比前一个更具有吸引力的细节; 这是一段摘录 。
显然 , 这个时钟返回的时间与任何现实世界的时间无关; 它只能用于比较同一个JVM实例中的时间戳 , 它相对于将来可能存在的任意“原点” , 因此它可能是负数 。 类似地currentTimeMillis , 该方法提供纳秒级精度 , 但不一定是纳秒级分辨率 。
System.nanoTime()纳秒时间只能用于测量时间间隔 , 所以它应该是单调的 , 对吧?不幸的是 , Javadoc没有说出单调性 , 所以下一步就是具体实现 。
Linux:
jlong os::javaTimeNanos() {  if (os::supports_monotonic_clock()) {
    struct timespec tp;
    int status = Linux::clock_gettime(CLOCK_MONOTONIC &tp);    assert(status == 0 \"gettime error\");
    jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);    return result;
   else {
    timeval time;
    int status = gettimeofday(&time NULL);    assert(status != -1 \"linux error\");
    jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);    return 1000 * usecs;
  

这是第一个惊喜:纳米时间确实是单调的 , 但只有底层操作系统支持它 。 公平地说 , 任何现代Linux服务器都支持CLOCK_MONOTONIC;
苹果系统:
jlong os::javaTimeNanos() {  const uint64_t tm = mach_absolute_time();  const uint64_t now = (tm * Bsd::_timebase_info.numer) / Bsd::_timebase_info.denom;  const uint64_t prev = Bsd::_max_abstime;  if (now <= prev) {    return prev;   // same or retrograde time;
    const uint64_t obsv = Atomic::cmpxchg(now &Bsd::_max_abstime prev);
  assert(obsv >= prev \"invariant\");   // Monotonicity
  // If the CAS succeeded then we're done and return \"now\".
  // If the CAS failed and the observed value \"obsv\" is >= now then
  // we should return \"obsv\".  If the CAS failed and now > obsv > prv then
  // some other thread raced this thread and installed a new value in which case
  // we could either (a) retry the entire operation (b) retry trying to install now

推荐阅读