当年偶然发现的 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
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();
}
}
命令行下编译、执行:
# 编译执行
$ javac FileTest.java && java FileTest
Windows 执行结果
Windows 平台不存在此 Bug。
# 编译执行
$ 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 最新版本,目前仍然没有修复该问题。
# 编译执行
$ 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 执行结果
# 编译执行
$ 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 已修复,但是之前版本目前仍然未修复。
微信公众号:daodaotest
当年偶然发现的 Java Bug(JDK 9及之前仍未修复)的更多相关文章
- Java的cmd配置(也即Java的JDK配置及相关常用命令)——找不到或无法加载主类 的解决方法
Java的cmd配置(也即Java的JDK配置及相关常用命令) ——找不到或无法加载主类 的解决方法 这段时间一直纠结于cmd下Java无法编译运行的问题.主要问题描述如下: javac 命令可以正 ...
- Java 序列化 JDK序列化总结
Java 序列化 JDK序列化总结 @author ixenos Java序列化是在JDK 1.1中引入的,是Java内核的重要特性之一.Java序列化API允许我们将一个对象转换为流,并通过网络发送 ...
- Java中JDK和JRE的区别是什么?它们的作用分别是什么?
JDK和JRE是Java开发和运行工具,其中JDK包含了JRE,但是JRE是可以独立安装的,它们在Java开发和运行的时候起到不同的作用~ 1.JDK JDK是Java Development Kit ...
- Java多线程--JDK并发包(2)
Java多线程--JDK并发包(2) 线程池 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. JDK有一套Executor框架,大概包括Executor.Ex ...
- 【转】Java中JDK和JRE的区别是什么?它们的作用分别是什么?
原文地址:http://blog.csdn.net/qq_33642117/article/details/52143824 JDK和JRE是Java开发和运行工具,其中JDK包含了JRE,但是JRE ...
- centos7中配置java + mysql +jdk +使用jar部署项目
centos7中配置java + mysql +jdk +使用jar部署项目 思维导图 1. 配置JDK環境 1.1下载jdk安装包 Java Downloads | Oracle 1.2 将下载j ...
- How to Install JAVA 8 (JDK/JRE 8u111) on Debian 8 & 7 via PPA
Oracle JAVA 8 Stable release has been released on Mar,18 2014 and available to download and install. ...
- 假设说这个世界不是真实存在的,仅仅是一段代码,迄今为止你发现了哪些bug?
给这个世界写代码的不是一个人,而是一个团队(这么大的项目,一个人开发不了).并且严重怀疑这个一个开源项目.开发人员被我们觉得是神,所以一神论是不正确的,众神论才是真理,且凡人是有机会成为神的(參悟神道 ...
- Java之.jdk卸载-Linux
Java之.jdk卸载-Linux 卸载Linux自带的jdk 首先查询: # rpm -qa | grep jdk 使用root账户,进行卸载: # yum -y remove xxxxxxxx( ...
随机推荐
- JAVA的基本程序设计结构(下)
字符串 Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义类,叫做 String. String e=""; //an empty String String ...
- Go语言入门系列(四)之map的使用
本系列前面的文章: Go语言入门系列(一)之Go的安装和使用 Go语言入门系列(二)之基础语法总结 Go语言入门系列(三)之数组和切片 1. 声明 map是一种映射,可以将键(key)映射到值(val ...
- 重写ThreadPoolTaskExecutor
目录 主类开启异步注解 创建线程池配置类 创建线程池实现类 创建一个测试类Controller 创建异步Service方法 定义异步的实现类 ThreadPoolExecutor:JDK内置线程池实现 ...
- 手写IOC实现过程
一.手写ioc前基础知识 1.什么是IOC(Inversion of Control 控制反转)? IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合.更优良 ...
- 博客主题推荐——复杂&简单
首先感谢原作者cjunn提供的主题autm,以下配置都基于此主题设定.很多小伙伴喜欢现在的样式,分享如下.只需简单几步即可. 如果你想使用本博客主题样式,并希望能得到远程推送更新,只需查看 快速部署. ...
- Java—API/Obiect类的equals toString方法/String类/StringBuffer类/正则表达式
API Java 的API(API: Application(应用) Programming(程序) Interface(接口)) 就是JDK中提供给我们使用的类,这些类将底层的代码实现封装了起来 ...
- C#LeetCode刷题之#9-回文数(Palindrome Number)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3840 访问. 判断一个整数是否是回文数.回文数是指正序(从左向右 ...
- 漏洞重温之XSS(上)
漏洞简介 跨站脚本攻击(XSS)是指恶意攻击者往Web页面里插入恶意Script代码,当用户浏览页面之时,嵌入web网页中的script代码会被执行,从而达到恶意攻击用户的目的. XSS漏洞通常是通过 ...
- SSRF 跨站请求伪造学习笔记
参考文章: 了解SSRF,这一篇就足够了 SSRF 学习之路 SSRF绕过方法总结 Weblogic SSRF漏洞 What-是什么 SSRF(Server-Side Request Forgery) ...
- GUAVA-ListenableFuture实现回调
随着软件开发的不断进步,在实际的开发应用中,可能一次请求需要查询若干次数据库或者调用若干次第三方,按照传统的串行执行的话,会大大增加响应时间,无法满足业务需求,更无法满足用户迫切需要响应迅速的愿望.对 ...