首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

System.nanoTime vs currentTimeMillis:納秒級計時、毫秒級時間戳、單位轉換與實戰選型指南

     編輯:Java 綜合教學

前言:兩個長得像、用途截然不同的方法

System.currentTimeMillis() 返回毫秒級時間戳 (1970 至今);System.nanoTime() 返回納秒級相對時間 (無絕對意義,僅用於測量間隔)。本文深度對比精度、用途、陷阱、單位轉換、實戰代碼模板,助你精準選型。

一、核心差異一覽表

維度currentTimeMillis()nanoTime()
語義牆鐘時間單調時鐘
基準點1970-01-01 00:00:00 UTCJVM 啟動/系統啟動 (實現相關)
返回值毫秒納秒 (10⁻⁹ 秒)
精度OS 依賴,通常 10-50msCPU 週期級,理論 1ns
單調性❌ 可被 NTP/用戶調時間倒退✅ 單調遞增 (不受調時間影響)
用途業務時間戳、日誌、緩存過期、日期顯示代碼執行耗時、基準測試、超時控制
轉 Datenew Date(ms) 直接轉無意義,不可轉
溢出292,278,994 年後 (long 極限)292 年後 (2⁶³ ns)

二、時間單位轉換速查 (必背)

1 秒  = 1,000 毫秒 (ms)
1 秒  = 1,000,000 微秒 (μs)
1 秒  = 1,000,000,000 納秒 (ns)
1 秒  = 1,000,000,000,000 皮秒 (ps)

1 分  = 60 秒
1 時  = 3,600 秒 = 3,600,000 ms

三、currentTimeMillis 實戰:業務時間戳、日期格式化、時間運算

long now = System.currentTimeMillis(); // 1705574400000

// 1. 轉 Date 格式化
Date date = new Date(now);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date)); // 2024-01-18 14:40:00

// 2. 時間運算:1 小時後 / 1 分鐘後
long oneHourLater = now + 3600 * 1000;      // + 1小時
long oneMinLater  = now + 60 * 1000;        // + 1分鐘
System.out.println(sdf.format(new Date(oneHourLater)));

// 3. 獲取系統屬性 (順帶)
System.out.println("OS: " + System.getProperty("os.name"));
System.out.println("User: " + System.getProperty("user.name"));

1小時後
1分鐘後

四、nanoTime 實戰:精準測量代碼耗時

// 標準測量模板
long start = System.nanoTime();
// ... 被測代碼 ...
long elapsedNs = System.nanoTime() - start;
double elapsedMs = elapsedNs / 1_000_000.0;
double elapsedSec = elapsedNs / 1_000_000_000.0;
System.out.printf("耗時: %.3f ms (%.6f s)%n", elapsedMs, elapsedSec);

// 實戰:比較兩個無序 String 數組是否相等 (利用異或特性)
public static boolean equals(String[] a, String[] b) {
    if (a.length != b.length) return false;
    int n = a[0].hashCode() ^ b[0].hashCode();
    for (int i = 1; i < a.length; i++) {
        n ^= a[i].hashCode() ^ b[i].hashCode();
    }
    return n == 0;
}

// 測試
String[] a = {"aaa", "aaa", "ccc"};
String[] b = {"aaa", "bbb", "ccc"};
long start = System.nanoTime();
boolean eq = equals(a, b);
long end = System.nanoTime();
System.out.println("結果: " + eq + ", 耗時: " + (end - start) + " ns");

五、常見陷阱與避坑

陷阱錯誤做法正確做法
用 currentTimeMillis 測微秒級耗時long t=System.currentTimeMillis(); ... System.currentTimeMillis()-t精度不夠,必用 nanoTime
用 nanoTime 存業務時間存入 DB 作為創建時間無絕對意義,**用 currentTimeMillis**
跨 JVM 比較 nanoTime兩服務器比較 nanoTime 差值基準點不同,**不可跨進程比較**
nanoTime 負值恐慌看到負數以為 Bug基準點可能在未來,**負值正常**,只關心差值
頻繁 new Date()循環中反複 new Date()提取 long now = System.currentTimeMillis() 復用

六、進階:JVM 實現差異 (HotSpot)

  • Linux/x86:nanoTime 讀取 clock_gettime(CLOCK_MONOTONIC) (vdso 加速,無系統調用開銷);currentTimeMillis 讀 gettimeofday / clock_gettime(CLOCK_REALTIME)。
  • Windows:nanoTime 用 QueryPerformanceCounter (高精度計數器);currentTimeMillis 用 GetSystemTimeAsFileTime (100ns 精度但粒度 ~15ms)。
  • 虛擬機/容器:單調時鐘通常正常,但遷移/快照可能導致 nanoTime 非單調 (極少見)。

七、總結:選型決策樹

需要「具體年月日時分秒」業務時間戳?
    ├─ 是 → System.currentTimeMillis()
    └─ 否 → 需要「測量間隔/耗時/超時/基準測試」?
              ├─ 是 → System.nanoTime()
              └─ 否 → 重新審視需求

一句话心法:牆鐘看 currentTimeMillis,碼表用 nanoTime。業務邏輯存毫秒戳,性能分析測納秒差。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved