Java并发:HashMap和ConcurrentHashMap的"get(Key)"在性能上是否相等?

5

当底层地图没有进行修改(只执行get()操作)时,标准HashMap和ConcurrentHashMap的get(Key)方法调用在性能上是否相等。

更新背景信息:

并发性是一个相当复杂的话题:我需要"并发/线程安全",但只在非常少的情况下进行puts操作。而对于puts操作,我可以交换地图的关联本身(这是原子和线程安全的)。

因此,我想知道当我执行大量的gets操作时,在使用HashMap(创建临时HashMap,将数据复制到新的HashMap中,并交换关联)和使用ConcurrentHashMap之间如何损失性能。

尽管听起来很傻,但互联网上有很多不必要的信息,但我认为这对很多人来说可能是有趣的。所以如果有人了解ConcurrentHashMap的内部工作原理,那么回答这个问题将会很好。

非常感谢!


2
ConcurrentHashMap是线程安全的。但每个操作都会带来一定的开销。除非您的应用程序90%的时间都在从中检索值,否则您不会注意到差异。 - user684934
你好,为什么我被踩了?请解释一下原因! - user1145216
1
你看过API了吗?它清楚地说明写入是同步的,而检索则不是。还有什么需要知道的吗? - blackcompe
获取数据的代码并不特别复杂,只需读取代码并做出明智的决定即可。 - Matt
3个回答

4

你问错了问题。

如果需要并发,无论性能影响如何都是必要的。

一个行为正确的程序几乎总是比一个更快的程序排名更高。我说“几乎总是”是因为可能存在商业原因发布带错误的软件而不是等待错误修复。


3
根据 ConcurrentHashMap API,检索方法没有锁定。因此,我认为它们的性能相等。

2

您可以查看源代码。(我正在查看JDK 6)HashMap.get()非常简单:

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }

hash()函数进行一些额外的移位和异或操作以“改进”哈希码。

ConcurrentHashMap.get()函数稍微复杂一些,但并不是太多。

public V get(Object key) {
    int hash = hash(key.hashCode());
    return segmentFor(hash).get(key, hash);
}

再次强调,hash()函数会进行一些移位和异或操作。setMentFor(int hash)函数只是简单的数组查找。唯一复杂的部分在于Segment.get()函数。但即使如此,它看起来也并不像什么高深的科学:

V get(Object key, int hash) {
   if (count != 0) { // read-volatile
      HashEntry<K,V> e = getFirst(hash);
      while (e != null) {
         if (e.hash == hash && key.equals(e.key)) {
            V v = e.value;
            if (v != null)
               return v;
            return readValueUnderLock(e); // recheck
          }
          e = e.next;
      }
 }
  return null;
}

它卡住的唯一地方是readValueUnderLock()。注释说这在内存模型下是合法的,但从未发生过。

总体而言,两者的代码看起来非常相似。ConcurrentHashMap只是更好地组织了一下。所以我猜性能应该足够相似。

话虽如此,如果put操作确实非常少,您可以考虑实现“写时复制”类型的机制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,