System.currentTimeMillis()是依赖于系统时钟的,也就是说,如果你把自己的系统时钟更改了,这个函数的返回会立即生效,变成更改后的值;
System.nanoTime()主要用于记录一个时间段的长度,或者说一个超时,在这个过程中,你更改系统时钟也不会影响。
两个方法的精度一个是毫秒,一个是纳秒,但都是不靠普的(有些系统的时间粒度是10ms),nanoTime()的调用也会消耗几微妙,所以不靠普;
但粒度不是我讨论的重点。
我们程序中的timer是很常用的功能,归根到底到下面的API:
LockSupport. public static void parkNanos(long nanos)
和
Thread.sleep(long millis)
不幸的是,但它们都是基于系统时钟的。
下面是我的测试,这个测试的过程是:启动后等待10秒钟,然后打印等待的时间:
public static void main(String[] args) throws InterruptedException {
long s = System.nanoTime();
int _10sec = 10 * 1000;
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(_10sec));
long e = System.nanoTime();
long used = e - s;
System.out.println("Used:" + TimeUnit.NANOSECONDS.toMillis(used));
}
在运行上面程序之后,在系统命令行执行下面命令重置时间:
[atlas@atlas-pc ~]$ date && sudo date -s 16:10:40 2013年 04月 10日 星期三 16:10:57 CST 2013年 04月 10日 星期三 16:10:40 CST
java程序输出:Used:27889
我把时钟向前拨了17s,一个park10s的程序27秒后才结束;
同样的,测试Thread:
public static void main(String[] args) throws InterruptedException {
long s = System.nanoTime();
int _10sec = 10 * 1000;
Thread.sleep(_10sec);
long e = System.nanoTime();
long used = e - s;
System.out.println("Used:" + TimeUnit.NANOSECONDS.toMillis(used));
}
运行后,重置时钟:
[atlas@atlas-pc ~]$ date && sudo date -s 16:33:40 2013年 04月 10日 星期三 16:34:03 CST 2013年 04月 10日 星期三 16:33:40 CST
java程序输出:Used:33569
这篇文章介绍了系统时钟和Java里面的几个API。
结论:
当我们重置服务器的时间(有些是通过网络同步的),
1,那些依赖系统时钟的程序(timer,scheduler,etc)会出现问题,
2,依赖时间判断的心跳会出问题,
目前还没有解放方法。