3

我们遇到了一个奇怪的问题。我们获得了 Oracle Coherence 缓存的 KeySet,但无法直接从缓存中获取值,即使它没有更新活动。

以下代码始终失败(即输出“>>>>NULL”,因为未检索到对象)。问题是:为什么?

    NamedCache nc = CacheFactory.getCache(cacheName);
    Set<Object> keys = (Set<Object>)nc.keySet();
    for ( Object key : keys ) {
        Object o = nc.get(key);
        if ( o == null ) {
            System.out.println(">>>>NULL:"+keyStr);
        } 
    }

缓存是具有多个索引的分区命名缓存。

关键是具有一个实例变量的对象(未显示),即 HashMap。

key 对象还具有 equals() 和 hashCode() 方法,如下所示:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((values == null) ? 0 : values.hashCode());
    return result;
}


@Override
public boolean equals(Object obj) {
    System.out.println("EQUALS");
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    AbstractCacheKey other = (AbstractCacheKey) obj;
    if (values == null) {
        if (other.values != null)
            return false;
    } else if (!values.equals(other.values))
        return false;
    return true;
}

我相信 Coherence 在此配置中使用序列化键对象的哈希,这将使这两种方法无关紧要,除非我不知道这对于前端缓存(本地 JVM,已关闭本地存储)和后端缓存(存储节点 JVM)。

我们的一些代码通过重建键、以标准顺序插入值来部分解决这个问题。这通常有效。我不明白为什么这是必要的,因为我们的 hashCode() 方法和 Java 的 hashCode() 用于 HashMap,AFAIK 对哈希的迭代顺序不敏感。为什么它通常但并不总是有效也是一个谜。

4

1 回答 1

2

答案(感谢 Dimitri)是HashMap不保证其序列化顺序,因此serialized-hash ->deserialize-> object-hash ->serialize-> serialized-hash可能导致第二个序列化哈希是不同的字节流比第一个。

Java 不保证散列中的排序,并且序列化依赖于排序。序列化可以从一个 JVM 到另一个不同,甚至在同一个 JVM 内。由于 HashMap 的内部实现是典型的内存哈希,有 N 个桶,每个桶(可能通过链表)持有一组条目,其哈希对应于桶,条目放入哈希的顺序决定(以非指定方式)键集迭代将返回它们的顺序。相比之下,TreeMap应该产生一致的顺序,因此可能产生一致的序列化。

Coherence 分区缓存以序列化的形式存储键和值,因此它们在键的序列化版本上计算哈希函数,并对序列化的键进行相等性检查。即使序列化流在重构对象方面是等效的,但不能保证与散列和相等检查操作所需的相同。

更复杂的是,在近缓存中,对象以反序列化形式保存,因此使用其equals()hashCode()方法。

最后,Coherence 推荐使用他们专有的 POF 序列化,这通常会减少序列化大小,并直接控制被序列化对象的序列化。

于 2012-02-26T03:38:26.913 回答