1. 程式人生 > >Java中的時間精度

Java中的時間精度

    在Java中可以通過System.currentTimeMillis()或者System.nanoTime() (JDK>=5.0) 方法獲得當前的時間的精確值。但是通過閱讀Javadoc,我們發現這兩個方法並不一定保證得到你所期望的精度。先來看System.currentTimeMillis():

Returns the current time in milliseconds. Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.

誠如上面所說返回值的粒度依賴於底層作業系統,那麼它在不同的平臺上到底能提供是麼樣的精度,是否像函式名所寫的那樣真正 確到1毫秒呢?看下面一段測試程式:

public class ClockAccuracyTest {

    public static void main(String args[]) {

        SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss:SSS");
        int size = 4000000;

        // create an array to hold millisecond times
        // and loop to capture them
        long times[] = new long[size];
        for (int i = 0; i < size; i++) {
            times[i] = System.currentTimeMillis();


        }

        // now display the unique times
        long time = times[0];
        long previousTime = times[0];
        long count = 0;
        Set<Long> deltas = new HashSet<Long>();       
        long delta = 0;
        long minDelta = Long.MAX_VALUE;
        long maxDelta = Long.MIN_VALUE;
        for (int i = 0; i < size; i++) {
            if (times[i] > time) {
                delta = time - previousTime;
                deltas.add(delta);
                if (delta > 0 && delta < minDelta) {
                    minDelta = delta;
                } else if (delta > maxDelta) {
                    maxDelta = delta;
                }

                System.out.print("raw=");
                System.out.print(time);
                System.out.print(" | formatted=");
                System.out.print(formatter.format(new Date(time)));
                System.out.print(" | frequency=");
                System.out.print(count);
                System.out.print(" | delta=");
                System.out.print(delta);
                System.out.println("ms");

                previousTime = time;
                time = times[i];
                count = 0;
            } else {
                count++;
            }
        }

        System.out.println("");
        System.out.println("Minimum delta : " + minDelta + "ms");
        System.out.println("Maximum delta : " + maxDelta + "ms");

    }

}

這段程式迴圈呼叫 System.currentTimeMillis()方法, 記錄並顯示結果,在我機器(Windows XP SP3)上執行輸出如下:

raw=1255659457187 | formatted=16-十月-2009 10:17:37:187 | frequency=147250 | delta=0ms
raw=1255659457203 | formatted=16-十月-2009 10:17:37:203 | frequency=447674 | delta=16ms
raw=1255659457218 | formatted=16-十月-2009 10:17:37:218 | frequency=436583 | delta=15ms
raw=1255659457234 | formatted=16-十月-2009 10:17:37:234 | frequency=439379 | delta=16ms
raw=1255659457250 | formatted=16-十月-2009 10:17:37:250 | frequency=426547 | delta=16ms
raw=1255659457265 | formatted=16-十月-2009 10:17:37:265 | frequency=447048 | delta=15ms
raw=1255659457281 | formatted=16-十月-2009 10:17:37:281 | frequency=459522 | delta=16ms
raw=1255659457296 | formatted=16-十月-2009 10:17:37:296 | frequency=414816 | delta=15ms
raw=1255659457312 | formatted=16-十月-2009 10:17:37:312 | frequency=458826 | delta=16ms

Minimum delta : 15ms
Maximum delta : 16ms

輸出的四列從左到右分別是原始的毫秒值、格式化的時間、每個值迴圈的次數、與上一個不同值的差。可以看到在Windows上 System.currentTimeMillis()方法並不能提供1ms的計時粒度,它的粒度為15~16ms,從網上的其它文章來看,這個結果基本上是一致的,這也驗證了Javadoc上所寫的“ the granularity of the value depends on the underlying operating system and may be larger ”。在其他作業系統,如Linux、Solaris上,我沒有進行測試,但從網上的一些測試結果看, currentTimeMillis方法在 某些作業系統能夠提供精確的1毫秒計時粒度。這是不是意味著Java在Windows上無法進行精確的毫秒計時了呢?當然不是,一種解決方案是採用JNI呼叫,利用Windows系統提供的函式計時;還有一個更簡便的辦法,就是使用JDK5.0加入的System.nanoTime()方法。Javadoc對該方法的描述如下:

Returns the current value of the most precise available system timer, in nanoseconds.

This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are made about how frequently values change. Differences in successive calls that span greater than approximately 292 years (263 nanoseconds) will not accurately compute elapsed time due to numerical overflow.

它返回系統能夠提供的最為精確的計時,以納秒(10億分之一秒)為單位,但並不保證納秒級精度。把上面的測試程式中黑體的一行改為“times[i] = System.nanoTime();”,並把所有的“ms”該成“ns”,迴圈次數改為10。執行輸出如下:

raw=8705892679376 | formatted=17-十一月-2245 23:31:19:376 | frequency=1 | delta=0ns
raw=8705892681053 | formatted=17-十一月-2245 23:31:21:053 | frequency=0 | delta=1677ns
raw=8705892682449 | formatted=17-十一月-2245 23:31:22:449 | frequency=0 | delta=1396ns
raw=8705892683846 | formatted=17-十一月-2245 23:31:23:846 | frequency=0 | delta=1397ns
raw=8705892685522 | formatted=17-十一月-2245 23:31:25:522 | frequency=0 | delta=1676ns
raw=8705892686919 | formatted=17-十一月-2245 23:31:26:919 | frequency=0 | delta=1397ns
raw=8705892688316 | formatted=17-十一月-2245 23:31:28:316 | frequency=0 | delta=1397ns
raw=8705892689713 | formatted=17-十一月-2245 23:31:29:713 | frequency=0 | delta=1397ns
raw=8705892691110 | formatted=17-十一月-2245 23:31:31:110 | frequency=0 | delta=1397ns

Minimum delta : 1396ns
Maximum delta : 1676ns

我們看到frequency=0,這意味著每執行一次迴圈,nanoTime方法的返回值都發生了改變,改變的差值平均大約為1467ns(不同效能的機器結果會不同)。這說明nanoTime方法計時的精度是非常高的,粒度比方法本身的呼叫執行耗時還要小。

回到上面的問題,如何在windows上實現精確的毫秒計時呢。答案就是用“System.nanoTime()/1000000L”代替“System.currentTimeInMills()”。把測試程式黑體的一行程式碼改為"times[i] = System.nanoTime()/1000000L;",迴圈次數5000,執行輸出結果如下:

raw=9487129 | formatted=01-一月-1970 10:38:07:129 | frequency=202 | delta=0ms
raw=9487130 | formatted=01-一月-1970 10:38:07:130 | frequency=704 | delta=1ms
raw=9487131 | formatted=01-一月-1970 10:38:07:131 | frequency=621 | delta=1ms
raw=9487132 | formatted=01-一月-1970 10:38:07:132 | frequency=618 | delta=1ms
raw=9487133 | formatted=01-一月-1970 10:38:07:133 | frequency=696 | delta=1ms
raw=9487134 | formatted=01-一月-1970 10:38:07:134 | frequency=695 | delta=1ms
raw=9487135 | formatted=01-一月-1970 10:38:07:135 | frequency=698 | delta=1ms
raw=9487136 | formatted=01-一月-1970 10:38:07:136 | frequency=698 | delta=1ms

Minimum delta : 1ms
Maximum delta : 1ms

我們看到粒度delta變為了1ms。迴圈次數frequency平均為676,也就是說每個迴圈運執行耗時1/676=0.001479ms=1479ns,與上一個測試結果的1467ns吻合。

結論:如果你的Java程式需要高精度的計時,如1毫秒或者更小,使用System.nanoTime()方法,它完全可以滿足你的需求。如果不行的話,建議你換臺更快的機器試試:)

相關推薦

Java時間

class api文檔 ast 天數 時間差 minimal bsp settime throw /** *觀看API文檔學習:Date中很多方法失效;Calendar頂替。 * **/import java.text.DateFormat;import java.t

java時間處理

ins hang 獲取 span cep color rac getc pan import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; i

java時間計算問題

.get bsp str gettime In cal ava main set 由於業務中有一項需求需要在新員工三個月快轉正的時候發郵件,所以寫個小例子看看效果時間在實體類中是long型,所以想的是先轉出date,用calender計算加75天之後再轉成String顯示

Java 時間處理 System.currentTimeMillis()

void ring row mem long long -m throws mes sim import org.testng.annotations.Test;import java.text.ParseException;import java.text.SimpleD

解決java丟失精度問題

解決java中丟失精度問題       在電商專案中遇到的問題,正常的float、double資料進行運算會出現精度丟失問題,在涉及貨幣計算時會出現嚴重後果。 程式碼: System.out.println(0.0

java時間如何比較大小

java中時間如何比較大小:         SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");    //設定日期格式     &nbs

java時間轉換】,當MM變成了mm,當DD變成了dd,會發生什麼事?

記自己一次無知的寫法,導致專案產生一個異常。下面拿出例項: 我負責接收介面傳遞過來的引數,做相應的轉換,出入資料庫中,一個時間的通過字串的形式傳遞過來,這個時間是24小時制,我的轉化如下: JSO

java計算精度問題的解決--BigDecimal類的使用

今天在學習的時候,第一次使用到BigDecimal類,特此記之。 很多人在利用java進行計算的時候經常會存在這樣一個問題: package calculate; import java.math.BigDecimal; public class Damo

JAVA時間與字串的相互轉換(工具類)

<span style="font-size:24px;">//model為字串的時間格式,如"<span style="font-family: arial; line-heigh

Java時間格式化(獲取指定時間

Java中時間格式化(獲取指定時間,七天前) 1、通過獲取當前系統時間,格式化後轉為“yyyy-MM-dd HH:mm:ss”格式並輸出; 2、可獲取指定時間,如七天前,一年前等,使用者通過時間段查

聊一聊Javadouble精度去哪了

前段時間, 因為要測試一個剛出爐的高頻策略, 放實盤去跑吧, 怕出岔, 所以寫了個簡單的回測系統, 跑一遍歷史資料. 其中有一部分是關於撮合系統, 簡陋了點, 還算能跑得起來, 幾個用例下來, 也沒什麼問題, 接著增加歷史資料量, 居然出現了負數, 簡直不可能發生的事情居然出現了, 雖然都是小金額的偏差,

Java時間API使用詳解

目錄 Java中時間API使用詳解 1. 時區概念 2. 幾種常見的時間 3. 時間戳 4. Java中的時間API 5. Java8中新新增的時間API 6.

Java時間精度

    在Java中可以通過System.currentTimeMillis()或者System.nanoTime() (JDK>=5.0) 方法獲得當前的時間的精確值。但是通過閱讀Javadoc,我們發現這兩個方法並不一定保證得到你所期望的精度。先來看System.c

Java時間精度 .System.currentTimeMillis() 、System.nanoTime() 方法 使用

 在Java中可以通過System.currentTimeMillis()或者System.nanoTime() (JDK>=5.0) 方法獲得當前的時間的精確值。但是通過閱讀Javadoc,我們發現這兩個方法並不一定保證得到你所期望的精度。先來看System.currentTimeMillis():

java如何在代碼判斷時間是否過了10秒

cal () bsp som ret pan div color end long previous = 0L; ... { Calendar c = Cale

java怎樣獲得當前日期時間

follow 樣本 cda set mon do-while 如果 xtend div Calendar cal = Calendar.getInstance(); java.text.SimpleDateFormat sdf = new SimpleDateF

JAVA日期和時間的格式化選項

println 對象 bsp lec pub cti class 日子 月份 一、使用printf方法 1 import java.util.Date; 2 import java.util.Scanner; 3 4 5 public class Test

JAVA獲取當前系統時間

arch tac 獲取 -m simple 得到 轉化 sel stack 一. 獲取當前系統時間和日期並格式化輸出: import java.util.Date;import java.text.SimpleDateFormat; public class NowStri

javadouble的精度去哪了[轉]

blank ble 四舍五入 img http 得到 .html 浮點 .com 我們知道,浮點數值采用二進制系統表示,二進制系統無法精確表示1/10,就好像十進制無法精確表示1/3 。 所以,我們采用四舍五入/保留小數位方式以獲得精簡數值。 那麽,問題來了

Java的高精度整數和高精度小數

整數測試 div string pac 高精 int trac print log 在實際編碼中,會遇到很多高精度的事例,比如,在計算金錢的時候就需要保留高精度小數,這樣計算才不會有太大誤差: 在下面的代碼中,我們驗證了,當兩個float型的數字相加,得到的結果和我們的預期