Java 提供相同哈希代码的两个不同类实例
我在JBoss服务器上遇到了一个奇怪的问题,其中两个类产生相同的Java 提供相同哈希代码的两个不同类实例,java,ognl,Java,Ognl,我在JBoss服务器上遇到了一个奇怪的问题,其中两个类产生相同的hashCode() 我通常不会在意,但我们使用的框架使用一个键缓存setter,该键由类中的哈希代码和属性名组成。这是一个糟糕的缓存设计,但目前我无法控制(最新的Struts 2.3.24版本中的OGNL 3.0.6,请参阅。较新的OGNL解决了这个问题,但它将在Struts中出现,直到2.5版本,目前处于测试阶段。) 让我觉得这个问题有点奇怪的是 使用几天后出现问题。。。我很确定在这段时间内,两个类/属性都被缓存了。这让我相信
hashCode()
我通常不会在意,但我们使用的框架使用一个键缓存setter,该键由类中的哈希代码和属性名组成。这是一个糟糕的缓存设计,但目前我无法控制(最新的Struts 2.3.24版本中的OGNL 3.0.6,请参阅。较新的OGNL解决了这个问题,但它将在Struts中出现,直到2.5版本,目前处于测试阶段。)
让我觉得这个问题有点奇怪的是
- 使用几天后出现问题。。。我很确定在这段时间内,两个类/属性都被缓存了。这让我相信类实例哈希代码实际上正在改变。。。几天后他们变得平等了
- 我们在一个非常过时的热点1.6中观察到了这种行为,现在在1.7.0_80上。两者都是基于Sun Sparc的32位构建
- JVM报告-XX:哈希代码为“0”
类
实例时是否使用特殊的hashcode处理
java.lang.Class
不会覆盖hashCode
,JVM也不会以某种方式专门处理它。这只是从java.lang.Object
继承的常规标识哈希代码-XX:hashCode=0
(JDK 6和JDK 7中的默认值)时,使用global Park Miller随机数生成器计算标识hashCode。该算法生成周期为2^31-2
的唯一整数,因此两个对象几乎不可能具有相同的hashCode,原因如下hashCode
方法时生成的。因此,何时以及如何加载类并不重要。如果同时调用hashCode
,则任何两个对象都可能发生此问题-XX:hashCode=5
(JDK 8中的默认值)。此选项使用线程本地Xorshift RNG。它不受竞赛条件的限制,并且比Park-Miller算法更快我认为它们不会随着时间的推移而改变。那太奇怪了。你能确认它们在一开始就不一样吗?@Thilo我不能100%地确定哈希代码并不总是一样的。我所知道的是,在试图设置框架操作属性时,我提到的缓存机制在这种情况下肯定会失败。从历史上看,这正是我们观察到的问题。我刚刚重新部署了,哈希代码是不同的。我只需要等待几天/几周,直到问题返回,然后再次运行类测试。这两个类是什么子类?它们可能有一个覆盖
hashCode()
@FSQ的父级,因为它们不是特定类的实例。它们是java.lang.Class
的实例,它是final
,并以本机方式生成哈希代码。标识哈希代码是一个非常小的数字,对我来说似乎很奇怪。哇,一个很好的解释!我非常怀疑类加载器是否以多线程方式初始化这些类。。。但你的解释使这一点无关紧要。很可能这些类的hashCode()是第一次被并发线程调用的,我同意这是唯一真正的解释。由于我们的框架限制,您更改哈希代码生成策略的解决方案是我的最佳选择。好极了!
Class<?> cl1 = Class.forName("fqn.Class1");
Class<?> cl2 = Class.forName("fqn.Class2");
out.println(cl1.getCanonicalName());
out.println(cl2.getCanonicalName());
out.println(cl1.hashCode());
out.println(cl2.hashCode());
out.println(System.identityHashCode(cl1));
out.println(System.identityHashCode(cl2));
out.println(cl1 == cl2);
out.println(cl1.equals(cl2));
out.println(cl1.getClassLoader().equals(cl2.getClassLoader()));
fnq.Class1
fnq.Class2
494722
494722
494722
494722
false
false
true