当前位置:  开发笔记 > 编程语言 > 正文

System.currentTimeMillis vs System.nanoTime

如何解决《System.currentTimeMillisvsSystem.nanoTime》经验,为你挑选了6个好方法。

如果您只是想要精确测量经过的时间,请使用System.nanoTime().System.currentTimeMillis()将为您提供自纪元以来最精确的可能的经过时间(以毫秒为单位),但System.nanoTime()相对于某个任意点,您可以获得纳秒精确的时间.

从Java文档:

public static long nanoTime()

返回最精确的可用系统计时器的当前值,以纳秒为单位.

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关.返回的值表示纳秒,因为某些固定但是任意时间(可能在将来,因此值可能为负).该方法提供纳秒精度,但不一定是纳秒精度.不保证值的变化频率. 由于数值溢出,跨越大于约292年(2 63纳秒)的连续调用的差异将无法准确计算经过的时间.

例如,要测量某些代码执行所需的时间:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

另请参阅:JavaDoc System.nanoTime()和JavaDoc System.currentTimeMillis()以获取更多信息.



1> dancavallaro..:

如果您只是想要精确测量经过的时间,请使用System.nanoTime().System.currentTimeMillis()将为您提供自纪元以来最精确的可能的经过时间(以毫秒为单位),但System.nanoTime()相对于某个任意点,您可以获得纳秒精确的时间.

从Java文档:

public static long nanoTime()

返回最精确的可用系统计时器的当前值,以纳秒为单位.

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关.返回的值表示纳秒,因为某些固定但是任意时间(可能在将来,因此值可能为负).该方法提供纳秒精度,但不一定是纳秒精度.不保证值的变化频率. 由于数值溢出,跨越大于约292年(2 63纳秒)的连续调用的差异将无法准确计算经过的时间.

例如,要测量某些代码执行所需的时间:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

另请参阅:JavaDoc System.nanoTime()和JavaDoc System.currentTimeMillis()以获取更多信息.


这个答案在选择nanoTime()时在技术上是正确的,但完全掩盖了极其重要的一点.正如文档所说,nanoTime()是一个精确计时器.currentTimeMillis()不是定时器,它是"挂钟".nanoTime()将始终产生正的经过时间,currentTimeMillis将不会(例如,如果您更改日期,点击闰秒等).对于某些类型的系统,这是一个非常重要的区别.
你确定你知道准确度和精度之间的区别吗?它不可能精确到纳秒精度.
用户更改时间和NTP同步确定,但为什么`currentTimeMillis`会因DST而改变?DST开关不会更改超过纪元的秒数​​.它可能是"挂钟",但它是基于UTC的挂钟.您必须根据您的时区和DST设置确定当地时间转换的内容(或使用其他Java实用程序为您执行此操作).
对不起,我的意思很精确.我使用松散的术语,但我同意这是令人困惑的(并且不正确地使用了这个词).
@dancavallaro,感谢您提供的信息.如果您不介意,我编辑了您的答案,以包含文档中的引用并修复链接
连续的电话,大约超过292年....我的新报价!

2> gubby..:

既然没有人提到过这个......

比较System.nanoTime()不同线程之间的调用结果是不安全的.即使线程的事件以可预测的顺序发生,纳秒的差异也可以是正的或负的.

System.currentTimeMillis() 在线程之间使用是安全的.


看看这里提到的描述:http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime(),看来nanoTime返回的值之间的差异是有效的只要它们来自同一个JVM就可以进行比较 - 只有当计算出在Java虚拟机的同一个实例中获得的两个这样的值之间的差异时,此方法返回的值才有意义.
[JavaDoc for`nanoTime()`](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#nanoTime--)说:*使用相同的来源在Java虚拟机的实例中调用此方法的所有内容; 其他虚拟机实例可能使用不同的来源.*这意味着它**会在线程中返回相同的内容.
在根据以下内容仅保留到SP2的Windows上:http://stackoverflow.com/questions/510462/is-system-nanotime-completely-useless
@jgubby:非常有趣......**任何对支持的引用_不能安全地比较不同线程之间的System.nanoTime()调用结果_?**以下链接值得一看:http://bugs.sun .com/bugdatabase/view_bug.do?bug_id = 6519418 http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime()
好吧,你每天都学到新东西.但我怀疑,鉴于它过去是不安全的(肯定会返回跨线程的无意义读数),这种用法可能仍然在规范之外,因此应该避免.
这不完全正确,nanoTime()在线程之间一致返回,除非您的系统有问题,这个数字将在调用之间按预期增加.另一方面,System.currentTimeMillis()甚至可以在同一个线程上向后跳转,因为它代表了挂起时间,可以通过外部因素(如NTP更新)进行调整.
我认为没有任何理由首先测量不同线程之间的时间.但不管怎样,我想在你的声明中添加一个"引用",即"System.nanoTime()"不是线程安全的.
这个答案是错误的。情况恰好相反:currentTimeMillis()也不是线程安全的(假定的含义,即单调非递减结果),即使在单个线程中也是如此。nanoTime()是线程安全的。

3> Michael Burr..:

Arkadiy更新:我System.currentTimeMillis()在Oracle Java 8中观察到Windows 7上更正确的行为.返回的时间精度为1毫秒.OpenJDK中的源代码没有改变,所以我不知道是什么原因造成了更好的行为.


孙大卫霍姆斯发布了博客文章一对夫妇多年前拥有的Java API的时机非常详细的外观(尤其是System.currentTimeMillis()System.nanoTime()),当你想使用的,以及它们如何在内部工作.

Hotspot VM内部:时钟,定时器和调度事件 - 第一部分 - Windows

对于具有定时等待参数的API,Java在Windows上使用的计时器的一个非常有趣的方面是,计时器的分辨率可以根据可能已经进行的其他API调用而改变 - 系统范围(不仅仅在特定进程中) .他展示了一个使用Thread.sleep()将导致此分辨率更改的示例.


我将currentTimeMillis跟踪到OpenJDK中的hotspot/src/os/windows/vm/os_windows.cpp中的os :: javaTimeMillis(http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/ OS /窗/ VM/os_windows.cpp#l833).看起来它仍然是GetSystemTimeAsFileTime,所以我不知道改变的来源.或者,如果它甚至有效.使用前测试.

4> Paul Morel..:

System.nanoTime()旧JVM不支持.如果这是一个问题,坚持下去currentTimeMillis

关于准确性,你几乎是正确的.在某些Windows机器上,currentTimeMillis()分辨率约为10毫秒(不是50毫秒).我不确定为什么,但有些Windows机器和Linux机器一样准确.

我过去使用GAGETimer取得了一定的成功.


"旧JVM"和哪些一样?Java 1.2还是什么?

5> KarlU..:

正如其他人所说,currentTimeMillis是时钟时间,由于夏令时,用户更改时间设置,闰秒和互联网时间同步而改变.如果您的应用依赖于单调增加的经过时间值,您可能更喜欢nanoTime.

你可能会认为玩家不会在游戏过程中摆弄时间设置,也许你是对的.但是,不要低估因互联网时间同步或远程桌面用户造成的中断.nanoTime API不受这种破坏的影响.

如果您想使用时钟时间,但避免因互联网时间同步导致的不连续性,您可能会考虑使用诸如Meinberg之类的NTP客户端,它将时钟频率"调整"为零,而不是仅定期重置时钟.

我是根据个人经验说的.在我开发的天气应用中,我随机发生风速峰值.我花了一段时间才意识到我的时基被典型PC上的时钟时间行为所扰乱.当我开始使用nanoTime时,我的所有问题都消失了.对于我的应用,一致性(单调性)比原始精度或绝对精度更重要.


*"currentTimeMillis是时钟时间,由于夏令时而改变"*...非常确定此语句是错误的.`System.currentTimeMillis()`报告自Unix/Posix Epoch(1970年1月1日午夜)以来的经过时间(以毫秒为单位).由于UTC永远不会针对夏令时进行调整,因此当本地时区为夏令时添加或偏移当地时间时,此值不会被抵消.此外,Java Time Scale平滑了闰秒,因此几天继续显示为86,400秒.

6> Lawrence Dol..:

是的,如果需要使用这种精度System.nanoTime(),但要注意您需要Java 5+ JVM.

在我的XP系统上,我看到使用以下代码报告的系统时间至少为100微秒 278 纳秒:

private void test() {
    System.out.println("currentTimeMillis: "+System.currentTimeMillis());
    System.out.println("nanoTime         : "+System.nanoTime());
    System.out.println();

    testNano(false);                                                            // to sync with currentTimeMillis() timer tick
    for(int xa=0; xa<10; xa++) {
        testNano(true);
        }
    }

private void testNano(boolean shw) {
    long strMS=System.currentTimeMillis();
    long strNS=System.nanoTime();
    long curMS;
    while((curMS=System.currentTimeMillis()) == strMS) {
        if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)); }
        }
    if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)+", Milli: "+(curMS-strMS)); }
    }

推荐阅读
帆侮听我悄悄说星星
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有