2 回答

TA貢獻(xiàn)1851條經(jīng)驗(yàn) 獲得超5個贊
終于有時間更深入地研究這個問題了。
我開始實(shí)驗(yàn),過了一段時間后發(fā)現(xiàn),實(shí)際上并不是System.out.println它的存在影響了結(jié)果,而是你LocalDateTime在它之前實(shí)例化了2個實(shí)例。
深入挖掘LocalDateTime和SystemClock(它所委托的) 的代碼,我發(fā)現(xiàn)亞毫級精度是通過調(diào)用本機(jī)調(diào)用 來實(shí)現(xiàn)的jdk.internal.misc.VM#getNanoTimeAdjustment。
最后一個調(diào)用是特定于操作系統(tǒng)的。我對它進(jìn)行了一些實(shí)驗(yàn),發(fā)現(xiàn)它不會線性返回值,因?yàn)樗谘h(huán)中被調(diào)用(假設(shè)我的循環(huán)運(yùn)行得相當(dāng)規(guī)律)。
所以我決定運(yùn)行一些代碼來映射返回的納米值。
我制作了這個示例代碼:
Clock clock = Clock.systemDefaultZone();
int samples = 1_000;
LocalDateTime[] instants = new LocalDateTime[samples];
int k = 0;
for (int i = 0; i < samples; i++) {
instants[i] = LocalDateTime.now(clock);
for (int j = 0; j < 10000; j++) {
k = j % 2;
}
}
將值寫入文件,然后將納米差異與第一個值映射到圖表中:
正如您所看到的,該圖(包含 1000 個值)會出現(xiàn)間歇性跳躍。這顯然部分是由于底層系統(tǒng)的精度限制造成的。但令我震驚的是,前兩個值始終不同。就好像在定期訪問時操作系統(tǒng)開始緩存該值一段時間(可能是為了避免系統(tǒng)資源緊張)。
但結(jié)果似乎是您設(shè)置自己在第三次和第四次調(diào)用時獲得相同的值(除非已經(jīng)過去了足夠的時間)。
這可以解釋為什么您的測試在沒有這些先前實(shí)例的情況下通過,而失敗。
順便說一句,對于單元測試,您不想依賴系統(tǒng)時鐘。確保您的業(yè)務(wù)代碼從注入的 Clock 實(shí)例獲取時間。然后,您可以注入自定義時鐘進(jìn)行測試,并測試您的代碼是否會在 DST 轉(zhuǎn)換日期或閏日運(yùn)行,而無需等待幾個月。

TA貢獻(xiàn)1847條經(jīng)驗(yàn) 獲得超7個贊
該測試涉及競爭條件并通過(有時),因?yàn)闀r間和添加語句會改變時間并因此改變測試結(jié)果。
斷言中檢查的條件基本上是連續(xù)兩個日期時間的納秒部分是否相等。
鑒于默認(rèn)情況下由System.currentTimeMillis()
內(nèi)部使用并且它最多具有毫秒精度,如果獲取納秒數(shù)的第二個調(diào)用序列足夠快(即導(dǎo)致在同一時間內(nèi)完成調(diào)用的LocalDateTime.now
實(shí)際調(diào)用序列),則檢查將成功。System.currentTimeMillis
毫秒作為第一個)。
當(dāng)您在實(shí)際斷言之前調(diào)用用于獲取納秒值的函數(shù)時,會加載相應(yīng)的類,相應(yīng)方法的代碼會進(jìn)入 CPU 緩存等。這使得第二對獲取納秒數(shù)的調(diào)用運(yùn)行得更快。
添加回答
舉報