`
dingjob
  • 浏览: 183296 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Map的HashCode做缓存key值引发的重大bug

阅读更多

现象:

计费和账户的交互通过Map来交互,基本数据格式如下{"pp900_88",20,"pp900_61",2……}

在不同的取值情况下,较多数据返回了相同的价格结果,导致计算价格错误。

 

应用场景:

产品计算价格时,使用cache缓存了价格结果数据,cache的key值是传入map的hashCode,本意是要实现完全相同的Map传入值从缓存取数据,减少数据库的访问。

 

 

原因分析:

 

一。通过如下代码模拟线上应用:

  public static void main(String[] args) {
        HashMap map = new HashMap();

        for(int i = 0 ; i < 100 ; i ++){

            HashMap m1 = new HashMap();

            m1.put("pp900_88", i);

            m1.put("pp900_59", 30);

            m1.put("pp900_62", 6);

            m1.put("pp900_63", 4);

            m1.put("pp900_60", "y");

            m1.put("pp900_61", i);

            int hs = m1.hashCode();

            map.put(hs, map.get(hs)+","+i);
            //            System.out.println(i+"==="+m1.hashCode());
        }
        System.out.println(map.size());
        System.out.println(map);
    }

 结果如下:

 

{-479160017=null,56,57,58,59,60,61,62,63,
 -479160049=null,40,41,42,43,44,45,46,47, 
 -479160033=null,48,49,50,51,52,53,54,55,
 -479160129=null,0,1,2,3,4,5,6,7,64,65,66,67,68,69,70,71,
 -479160097=null,16,17,18,19,20,21,22,23,80,81,82,83,84,85,86,87,
 -479160113=null,8,9,10,11,12,13,14,15,72,73,74,75,76,77,78,79,
 -479160065=null,32,33,34,35,36,37,38,39,96,97,98,99, 
 -479160081=null,24,25,26,27,28,29,30,31,88,89,90,91,92,93,94,95}

 

可以看到,重复是很有规律的,连续7、8个数据都是重复的,当然在真实情况下重复概率不会这么高(因为Map的其他key-value值不太可能完全相同)

 

二。分析hashCode的产生

HashMap的hashCode根据key和value值来计算hashCode,最后将各个元素的hashCode值相加,即

 public final int hashCode() {
            return (key==null   ? 0 : key.hashCode()) ^
                   (value==null ? 0 : value.hashCode());
        }

 

以  m1.put("pp900_88", 1);  m1.put("pp900_61", 1);和

     m1.put("pp900_88", 2);  m1.put("pp900_61", 2);为例子:得到的key-Value的hashCode值如下

 

key                   key的hashCode   value的hashCode  Map的hashCode(key^value)

  pp900_88        -79859962             1                       -79859961

  pp900_61        -79860031             1                       -79860032
  pp900_88        -79859962             2                       -79859964
  pp900_61        -79860031             2                       -79860029
 
显然根据Map的hash值算法, Map的hashCode相加:第一行+第二行=第三行+第四行,这样产生重复数据也在所难免了,因为hashCode本来就不保证不同的输入值不会产生相同的结果。JSL的约束是对于相同的对象,必须产生相同的hashCode。
结论和改进措施:
1.不建议对结果进行缓存,结果缓存会带来很多问题,比如哪些数据变更需要刷新哪些缓存,缓存最好对原始纪录值进行缓存。
2.key值不采用hashCode算法,直接改为使用各个key-value的String拼接字符串。
 

 

分享到:
评论

相关推荐

    深入 HashCode 方法~

    - 对于不同的类,默认情况下,`hashCode()` 方法的实现可能会有所不同,但通常会依赖于对象的一些关键属性来生成一个整数值作为 `HashCode`。 2. **自定义类中的 HashCode 实现**: - 当我们自定义一个类时,通常...

    equals与hashCode方法讲解

    return Objects.hashCode(key) ^ Objects.hashCode(value); } equals 方法和 hashCode 方法都是用于比较两个对象是否相等的,但它们的实现方式不同。equals 方法是比较两个对象的内容是否相等,而 hashCode 方法是...

    HashCode的用法详解

    hashCode 的用法详解 hashCode 是一种用于查找和排序的机制,在数据结构中 plays a crucial role。下面我们将对 hashCode 的用法进行详细的解释。 hashCode 的作用 hashCode 的主要作用是用于查找和排序。在查找...

    hashcode的作用

    在Java中,`hashCode()` 方法是 `Object` 类的一个重要成员方法,它返回一个整数,这个整数通常用来表示对象的哈希值。哈希值在Java集合框架中扮演着至关重要的角色,尤其是在散列表(如 `HashMap` 和 `Hashtable`)...

    深入HashCode

    在哈希表中,`hashCode()`被用来计算对象存储的位置,因为哈希表通过对象的哈希值来确定其存储位置,从而实现快速查找。理想情况下,不同的对象应有不同的哈希码,但相同的对象(根据`equals()`方法判断相等)必须...

    浅谈Java中hashCode的正确求值方法

    浅谈Java中hashCode的正确求值方法 hashCode是一种常用的散列函数,在Java中它是一个对象的整数表示,用于标识对象的唯一性。在Java中,每个对象都有一个hashCode,这个hashCode可以通过hashCode()方法来获取。...

    java中Hashcode的作用.docx

    1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。 2. 如果两个对象根据equals(Object o)方法是相等的,...

    hashCode的作用

    这是因为,如果两个相等的对象具有不同的`hashCode`值,可能会导致在某些场景下出现问题,比如在`HashSet`或`HashMap`中无法正确识别相等的对象。 #### 5. 示例代码解析 以下是一段示例代码,展示了如何使用`...

    Android 对Map按key和value分别排序的实例

    一. 理论准备 ...HashMap的值是没有顺序的,它是按照key的HashCode来实现的,对于这个无序的HashMap我们要怎么来实现排序呢?参照TreeMap的value排序。 Map.Entry返回Collections视图。 二. key排序 Tr

    地图的简单使用(Map)

    在编程领域,`Map`是一种数据结构,它存储键值对,允许我们通过键来查找对应的值。在各种编程语言中,如Java、C++、Python等,都有类似的概念。`Map`通常用于关联特定的值与特定的键,使得在处理大量数据时能快速...

    重写equals和hashcode方法_equals_重写equals和hashcode方法_

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中的两个核心方法,所有类都默认继承自Object类。这两个方法在处理对象比较和集合操作时起着至关重要的作用。当我们创建自定义类并需要对对象进行精确...

    Glide如何访问已经下载到本地的缓存文件(图片地址若过期自己选别的)

    然而,SHA-256是一个强加密算法,如果我们想根据图片URL的MD5值来查找缓存,我们需要自定义这个key生成过程。 为实现这个目标,我们需要创建一个新的`KeyGenerator`类,这里称为`SafeKeyGenerator`,并让它继承自...

    java中Map映射机制

    Java中的Map映射机制是Java集合框架的重要组成部分,它提供了键值对的存储方式,使得可以通过键来查找和操作对应的值。Map接口是所有映射类的基础,它定义了多种方法来实现对键值对的操作。 Map接口的核心方法包括...

    java中map集合的用法.pdf

    Map集合不按照特定顺序存储元素,而是通过键(Key)来查找对应的值(Value)。以下是对Map接口及其常用实现类的详细说明: 1. **声明Map**: 创建Map实例时,通常使用HashMap作为默认实现。例如: ```java Map, ...

    java中map集合的用法

    - `put(K key, V value)`: 将指定的键值对放入Map中,如果键已经存在,则替换旧值。 - `get(Object key)`: 返回与指定键关联的值,如果不存在则返回null。 - `containsKey(Object key)`: 检查Map是否包含指定的键。 ...

    java中map集合的用法.doc

    Map不同于List,List是以索引来访问元素,而Map则是通过键(key)来查找对应的值(value)。Map接口定义了一系列方法,使得我们可以对键值对进行插入、删除、修改和查找等操作。 1. **创建Map实例**: 创建一个Map...

    Java Map 集合类简介

    其中,`equals(Object o)`和`hashCode()`方法用于比较Map的等价性,确保了Map的正确比较和存储。插入和删除元素的操作由`put(Object key, Object value)`、`remove(Object key)`以及`clear()`等方法完成。`putAll...

    复写hashCode()方法,和equasl()方法

    反之,如果两个对象的`hashCode()`值相同,则还需要进一步通过`equals()`方法来确定这两个对象是否真正相等。 #### 实现细节 在上面的代码示例中,`Person1`类重写了`hashCode()`方法: ```java public int ...

    java中hashcode()和equals()方法详解

    - 如果两个对象不相等(即`equals()`返回`false`),它们的`hashCode()`值不一定不同,但最好尽量让它们不同,以减少哈希冲突。 #### `equals()`方法 `equals()`方法同样定义于`Object`类中,用于判断两个对象是否...

Global site tag (gtag.js) - Google Analytics