System.currentTimeMillis() 和 System.nanoTime() 哪個更快?別用錯了!

作者:捏造的信仰
來源:https://segmentfault.com/a/1190000041276485

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。

近期熱文推薦:

1.1,000+ 道 Java面試題及答案整理(2022最新版)

2.勁爆!Java 協程要來了。。。

3.Spring Boot 2.x 教程,太全了!

4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這纔是優雅的方式!!

5.《Java開發手冊(嵩山版)》最新發布,速速下載!

覺得不錯,別忘了隨手點贊+轉發哦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章