Hashmap的性能因密钥

时间:2016-07-22 00:29:02

标签: java hashmap

我正在尝试通过hibernate将从DB获取的大约500万个对象加载到一个hashmap中。我为2种类别(A& B)执行此操作。我遍历了pojos。 Key是pojo中的一个字段,值是pojo本身。

1。对于A类类型,键是整数字段。我可以在不到20秒的时间内加载地图。

对于B类2.a)测试1,我的键是一个字符串字段。当我尝试将这些对象加载到新的hashmap时(通过重新启动java进程进行重新尝试,所以不用担心GC),将100K对象加载到地图中大约需要30秒。
2.b)测试2,当我尝试使用此类中的不同字段(整数类型)并加载地图时,它的工作方式与第一个类似,并且在不到20秒的时间内加载。
2.c)测试3,我想知道问题是否是数据类型。所以对于B类,我尝试了另一种使用#2.b中的整数字段创建字符串键的方法。 (key = int_field +“”)并将其加载到< 20秒

另一个测试,测试4,我为类B类做的是我创建密钥的方式。对于2.c,我创建了这样的键      map.put(pojo.getIntField()+“”,pojo);
结果如上所述2.c.

2.d)但是当我在pojo中创建另一个getter时返回 int_field +“”并在地图中使用它作为
map.put(pojo.getIntFieldInStringForm(),pojo);
对于100K物体,性能恶化到约30秒。

我知道问题出在密钥上,因为我已经通过将结果对象添加到列表中来验证数据库提取阶段,并且它在<两种类型均为20秒。

我无法理解其原因。如果有人能够对此有所了解,那将会非常有帮助。非常感激。感谢

编辑: 在这里添加代码片段(原谅格式/拼写错误,如果有的话):
测试#1

Map<String, ClassA> map = new HashMap<String, ClassA>();
Session session = sessionFactory.openNewSession();
try {
    Iterator<ClassA> iterator = session.createQuery( "from ClassA" ).setFetchSize( 1000 ).iterate();
    while ( iterator.hasNext() ) {
        ClassB objClassA = iterator.next();
        map.put( objClassB.getIntField(), objClassA );              
    }
}
catch (Exception e) {
    e.printStackTrace();
}
finally {
    session.close();
}

测试#2.a

Map<String, ClassB> map = new HashMap<String, ClassB>();
Session session = sessionFactory.openNewSession();
try {
    Iterator<ClassB> iterator = session.createQuery( "from ClassB" ).setFetchSize( 1000 ).iterate();
    while ( iterator.hasNext() ) {
        ClassB objClassB = iterator.next();
        map.put( objClassB.getStringField(), objClassB );               
    }
}
catch (Exception e) {
    e.printStackTrace();
}
finally {
    session.close();
}

测试#2.b

Map<Integer, ClassB> map = new HashMap<Integer, ClassB>();
Session session = sessionFactory.openNewSession();
try {
    Iterator<ClassB> iterator = session.createQuery( "from ClassB" ).setFetchSize( 1000 ).iterate();
    while ( iterator.hasNext() ) {
        ClassB objClassB = iterator.next();
        map.put( objClassB.getIntField(), objClassB );              
    }
}
catch (Exception e) {
    e.printStackTrace();
}
finally {
    session.close();
}


测试#2.c

Map<String, ClassB> map = new HashMap<String, ClassB>();
Session session = sessionFactory.openNewSession();
try {
    Iterator<ClassB> iterator = session.createQuery( "from ClassB" ).setFetchSize( 1000 ).iterate();
    while ( iterator.hasNext() ) {
        ClassB objClassB = iterator.next();
        map.put( objClassB.getIntField() + "", objClassB );             
    }
}
catch (Exception e) {
    e.printStackTrace();
}
finally {
    session.close();
}


测试#2.d

Map<String, ClassB> map = new HashMap<String, ClassB>();
Session session = sessionFactory.openNewSession();
try {
    Iterator<ClassB> iterator = session.createQuery( "from ClassB" ).setFetchSize( 1000 ).iterate();
    while ( iterator.hasNext() ) {
        ClassB objClassB = iterator.next();
        map.put( objClassB.getIntFieldInStringForm() + "", objClassB );             
    }
}
catch (Exception e) {
    e.printStackTrace();
}
finally {
    session.close();
}

1 个答案:

答案 0 :(得分:1)

要将项目放在HashMap中,需要计算密钥的hashCode。如果您的字符串是8 - 10个字符,则需要进行一些计算以将它们映射到32位哈希码。你的整数键有多大?如果它们小于100.000,则只有5个字符来计算hashCode,因此速度要快一些。

当两个键计算相同的哈希码时,您的性能也会受到影响,这可能会使用您的String键几次。

当您使用唯一整数作为键时,哈希冲突永远不会发生。也许如果您使用转换为整数的字符串,则字符串哈希算法也会减少冲突。