1. 程式人生 > >當年偶然發現的 Java Bug(JDK 9及之前仍未修復)

當年偶然發現的 Java Bug(JDK 9及之前仍未修復)

# 背景 15年在中信銀行做持續整合時,由於當時的專案是基於三方採購的 Java 配置開發平臺做的,平臺自己基於 ```Ant``` 外掛實現了增量和熱部署。 其中有幾個專案在持續整合部署時,經常發現 ```Linux``` 平臺部署成功後(```Windows``` 不會出現,```Linux``` 也是偶發現象),新版本程式碼並沒有生效(反編譯 class)。 起初我是在本地 ```windows``` 上跟蹤除錯基於 ```Ant``` 外掛的程式碼,但始終重現不了(最後測試發現 Windows 無此 Bug)。 後來,通過分析程式碼邏輯,其中有段邏輯是通過檔案的最後修改時間(```File.lastModified()```)來判斷要不要覆蓋部署的,最後通過單測發現,是由於 ```Java``` 的 ```File.lastModified()``` 方法在 ```Windows``` 和 ```Linux/Unix``` 平臺獲取的精度不一樣導致的,```Windows``` 精度為毫秒,而 ```Linux/Unix``` 只能到秒(JDK Bug:JDK-8177809)。 所以也解釋了,為什麼是偶發現象,檔案修改時間如果判斷的兩個值正好跨秒時,部署就是成功的,否則失敗。 # Bug 重現 **測試程式碼:FileTest.java** ```java import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.text.SimpleDateFormat; public class FileTest { private static final long LM = 1599276952718L; public static void main(String[] args) throws IOException { // java版本號 System.out.println("Java Version:" + System.getProperty("java.version")); File f = new File("test.txt"); f.createNewFile(); // 設定最後修改時間 f.setLastModified(LM); // 獲取修改時間,存在 bug System.out.printf("Test f.lastModified [%s]: %b\n", f.lastModified(), f.lastModified() == LM); // 格式化輸出,正確不存在 bug System.out.printf("Test f.lastModified DateFormat [%s]\n",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss").format(f.lastModified())); // Files.getLastModifiedTime() 獲取修改時間,同樣存在 bug System.out.printf("Test Files.getLastModifiedTime [%s]: %b\n", Files.getLastModifiedTime(f.toPath()).toMillis(), (Files.getLastModifiedTime(f.toPath()).toMillis() == LM)); // 格式化輸出,正確不存在 bug System.out.printf("Test Files.getLastModifiedTime DateFormat [%s]\n",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss").format(f.lastModified())); f.delete(); } } ``` 命令列下編譯、執行: ```bash # 編譯執行 $ javac FileTest.java && java FileTest ``` ## Windows 執行結果 Windows 平臺不存在此 Bug。 ```bash # 編譯執行 $ javac FileTest.java && java FileTest Java Version:1.8.0_202 Test f.lastModified [1599276952718]: true Test f.lastModified DateFormat [2020-09-05 11:35:52.052] Test Files.getLastModifiedTime [1599276952718]: true Test Files.getLastModifiedTime DateFormat [2020-09-05 11:35:52.052] ``` ## Mac 執行結果 JDK 8 最新版本,目前仍然沒有修復該問題。 ```bash # 編譯執行 $ javac FileTest.java && java FileTest Java Version:1.8.0_261 Test f.lastModified [1599276952000]: false Test f.lastModified DateFormat [2020-09-05 11:35:52.052] Test Files.getLastModifiedTime [1599276952000]: false Test Files.getLastModifiedTime DateFormat [2020-09-05 11:35:52.052] ``` ## Linux 執行結果 ```bash # 編譯執行 $ javac FileTest.java && java FileTest Java Version:1.8.0_171 Test f.lastModified [1599276952000]: false Test f.lastModified DateFormat [2020-09-05 11:35:52.052] Test Files.getLastModifiedTime [1599276952000]: false Test Files.getLastModifiedTime DateFormat [2020-09-05 11:35:52.052] ``` # 官方 Bug 連結 JDK10 已修復,但是之前版本目前仍然未修復。 - https://bugs.openjdk.java.net/browse/JDK-8177809 > 微信公眾號:da