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