这是一个困扰了我接近半个月的生产bug。当问题出现后,采取的措施分别是:打印日志,再仍然查不出问题后,改用其他方式实现,先保证不会对用户使用该系统数据照成影响。
在经过两天时间的跟踪,终于找到问题的根源。详细记录如下:
代码在字符串时逻辑里面用到了 StringUtils.contains() 方法,而这个方法主要是调用 String.indexOf() 方法, 如“ ,A,B,C,D,".indexOf("A") > 0 返回 true ; "A,B,C,D,".indexOf("E") 返回 false 。经过代码分析,结论是这个方法在参数完全一样的情况下运行结果出现了不一致的情况。在 oracle 的官网上查找 jdk 的 bug 库发现了与 String.indexOf ()方法相关的重要的 bug 记录:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6935535
内容是: String.indexOf() returns incorrect result on x86 with SSE4.2 。决定在生产上重现这个 bug ,于是把如下的代码放在生产上测试。
测试代码:
public class Test{ static int IndexOfTest(String str) { return str.indexOf("1111111111111xx1x"); } public static void main(String args[]) { String str = "1111111111111xx1111111111111xx1x"; str = str.substring(0, 31); int idx = IndexOfTest(str); System.out.println("IndexOf(" + "1111111111111xx1x" + ") = " + idx + " in " + str); } }
这段代码正确的结果应该是:-1 ,经过两次测试结果如下:
命令:java test
输出:IndexOf(1111111111111xx1x)= -1 in 1111111111111xx1111111111111xx1x
命令:java -XX:+UseSSE42Intrinsics -Xcomp test
输出:IndexOf(1111111111111xx1x)= 15 in 1111111111111xx1111111111111xx1x
生产上的 java 版本: java version "1.6.0_20" , CPU 架构: x86_64 GNU/Linux ,指令集包含: sse4_2
然后,又在 java version "1.6.0_25" 生产机器上运行,结果是正确的。
解决indexOf的方案,可采用如下方法中的一种:
1. 升级 JDK 版本到 1.6.0_25 ;
2. 在 java 启动行加上参数: -XX:-UseSSE42Intrinsics 。