System.currentTimeMillis() 和 System.nanoTime() 哪个更快?别用错了!

简介: System.currentTimeMillis() 和 System.nanoTime() 哪个更快?别用错了!

Java有两个取时间戳的方法:System.currentTimeMillis() 和 System.nanoTime(),它们的使用场景是有区别的,当前网上一些文章对于这两个方法的性能讨论存在一些片面的描述,本文希望能给出一个简单的最终答案。


System.currentTimeMillis() 存在性能问题?


答案是否定的。这两个方法性能差异取决于操作系统。


Windows:


在 Windows 下,System.currentTimeMillis() 比 System.nanoTime() 要快很多,这是因为 Windows 系统为前者提供的只是一个缓存变量,而后者则是实时的去硬件底层获取计数。


所以如果你的生产环境是 Windows,请尽可能避免使用 System.nanoTime()。


Linux:


在 Linux 下,两者的执行耗时相差不大,不论是单线程还是多线程。


不同的虚拟机实现会带来性能差异


如今的云主机主要有 Xen 和 KVM 两种实现方式,网上有文章发现它们在取系统时间方面存在性能差异。


当你的虚拟机用的是 Xen 时,取时间的耗时会是 KVM 的十倍以上。不过上文也提供了遇到此类问题该如何解决的方案。


需要写一个专门的类来提升 System.currentTimeMillis() 性能吗?

不需要。那属于画蛇添足。


我的测试代码


我的测试代码如下,没有任何依赖,可以直接用 javac 编译然后运行。读者有兴趣可以试试:


import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class TimePerformance {
    public static final int LOOP_COUNT = 9999999;
    public static final int THREAD_COUNT = 30;
    public static void main(String[] args) {
        Runnable millisTest = () -> {
            long start = System.currentTimeMillis();
            for (int i = 0; i < LOOP_COUNT; i++) {
                System.currentTimeMillis();
            }
            long end = System.currentTimeMillis();
            System.out.printf("%s : %f ns per call\n",
                    Thread.currentThread().getName(), ((double)end - start) * 1000000 / LOOP_COUNT);
        };
        Runnable nanoTest = () -> {
            long start = System.currentTimeMillis();
            for (int i = 0; i < LOOP_COUNT; i++) {
                System.nanoTime();
            }
            long end = System.currentTimeMillis();
            System.out.printf("%s : %f ns per call\n",
                    Thread.currentThread().getName(), ((double)end - start) * 1000000 / LOOP_COUNT);
        };
        Consumer<Runnable> testing = test -> {
            System.out.println("Single thread test:");
            test.run();
            System.out.println(THREAD_COUNT + " threads test:");
            List<Thread> threads = new ArrayList<>();
            for (int i = 0; i < THREAD_COUNT; i++) {
                Thread t = new Thread(test);
                t.start();
                threads.add(t);
            }
            // Wait for all threads to finish
            threads.forEach(thread -> {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        };
        System.out.println(" Test System.nanoTime()");
        testing.accept(nanoTest);
        System.out.println(" Test System.currentTimeMillis()");
        testing.accept(millisTest);
    }
}


因为我用的是 Windows,所以执行输出当中 System.nanoTime() 明显非常慢。


具体输出内容我就不放出来了,因为不具有参考价值,大多数生产环境用的是 Linux。


相关文章
|
安全 Java
灵魂拷问:你真的理解System.out.println()打印原理吗?
灵魂拷问:你真的理解System.out.println()打印原理吗?
134 0
out.println()爆红解决方法
out.println()爆红解决方法
276 0
|
监控 安全 Java
JDK源码(18)-System
JDK源码(18)-System
142 0
|
JavaScript Dubbo 小程序
还在用 System.currentTimeMillis() 统计代码耗时?太 Low 啦
还在用 System.currentTimeMillis() 统计代码耗时?太 Low 啦
|
缓存 Java Linux
注意了!System.currentTimeMillis() 存在性能问题...
System.currentTimeMillis()是极其常用的基础Java API,广泛地用来获取时间戳或测量代码执行时长等,在我们的印象中应该快如闪电。 但实际上在并发调用或者特别频繁调用它的情况下(比如一个业务繁忙的接口,或者吞吐量大的需要取得时间戳的流式程序),其性能表现会令人大跌眼镜。
注意了!System.currentTimeMillis() 存在性能问题...
TLA+ Specifying System (2)
TLA+ Specifying System (2)
TLA+ Specifying System (2)
|
Java Spring
别再用System.currentTimeMillis()!拥抱StopWatch优雅计算程序执行耗时
别再用System.currentTimeMillis()!拥抱StopWatch优雅计算程序执行耗时
153 0
|
程序员 开发工具 C语言
TLA+ Specifying System (1)
TLA+ Specifying System (1)
|
Java Unix Linux
JVM源码分析之System.currentTimeMillis及nanoTime原理详解
##概述 上周`@望陶`问了我一个现象很诡异的问题,说JDK7和JDK8下的`System.nanoTime()`输出完全不一样,而且差距还非常大,是不是两个版本里的实现不一样,之前我也没注意过这个细节,觉得非常奇怪,于是自己也在本地mac机器上马上测试了一下,得到如下输出: ``` ~/
7422 0