System.currentTimeMillis()是依赖于系统时钟的,也就是说,如果你把自己的系统时钟更改了,这个函数的返回会立即生效,变成更改后的值;
System.nanoTime()主要用于记录一个时间段的长度,或者说一个超时,在这个过程中,你更改系统时钟也不会影响。
两个方法的精度一个是毫秒,一个是纳秒,但都是不靠普的(有些系统的时间粒度是10ms),nanoTime()的调用也会消耗几微妙,所以不靠普;
但粒度不是我讨论的重点。
我们程序中的timer是很常用的功能,归根到底到下面的API:
LockSupport. public static void parkNanos(long nanos)
和
Thread.sleep(long millis)
不幸的是,但它们都是基于系统时钟的。
下面是我的测试:
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,依赖时间判断的心跳会出问题,
目前还没有解放方法。