Java ConcurrentHashMap优于HashMap性能吗?

Alv*_*vin 22 java concurrency performance hashmap data-structures

我刚刚阅读了"清洁代码"一书,并发现了这一说法:

当Java年轻的时候,Doug Lea写了一本开创性的书[8] Java中的Concurrent Programming.随着这本书,他开发了几个线程安全的集合,后来成为了JDK的 java.util.concurrent一部分.该软件包中的集合对于多线程情况是安全的,并且它们表现良好.事实上,ConcurrentHashMap 几乎所有情况下, 实现都比HashMap表现更好.它还允许同时并发读取和写入,并且它具有支持常见复合操作的方法,否则这些操作不是线程安全的.如果Java 5是部署环境,请从 ConcurrentHashMap

请注意,在上面的引用中,我使用了"[n]",其中n是某个数字,表示作者提供引用的地方,正如您所看到的,他没有为粗体部分提供任何参考.

并不是说我不相信这个陈述,但我很想知道这个陈述的支持证据.因此,没有人知道,显示了两种性能统计信息的任何资源ConcurrentHashMapHashMap?或者任何人都可以向我解释为什么ConcurrentHashMap比HashMap更快?

我可能会在休息时看看ConcurrentHashMap在工作中的实现,但是现在我想听听其他SOers的答案.

Ber*_*ann 11

如果您只使用单个线程访问HashMap,HashMap最快(它不会执行任何同步),如果您从多个线程访问它,ConcurrentHashMap比手动粗粒度同步更快.请看这里进行一些比较:

http://www.codercorp.com/blog/java/why-concurrenthashmap-is-better-than-hashtable-and-just-as-good-hashmap.html

  • 但是作者似乎建议使用ConcurrentHashMap,即使是单线程情况. (2认同)

irr*_*ble 10

Doug Lea非常擅长这些事情,所以如果有一次他的ConcurrentyHashMap比Joshua Bloch的HashMap表现得更好,我也不会感到惊讶.但是从Java 7开始,H​​ashMap的第一个@author也成了Doug Lea.显然现在HashMap没有理由比它的同伴堂兄慢.

出于好奇,我还是做了一些基准测试.我在Java 7下运行它.条目越多,性能越接近.最终ConcurrentHashMap在HashMap的3%范围内,这是非常了不起的.瓶颈实际上是内存访问,俗话说"内存是新磁盘(磁盘是新磁带)".如果条目在缓存中,则两者都会很快; 如果条目不适合缓存,则两者都会很慢.在实际应用程序中,映射不一定要与其他人竞争驻留在缓存中.如果经常使用地图,它会被缓存; 如果没有,它不会被缓存,这是真正的决定因素,而不是实现(两者都由同一专家实现)

public static void main(String[] args)
{
    for(int i = 0; i<100; i++)
    {
        System.out.println();

        int entries = i*100*1000;
        long t0=test( entries, new FakeMap() );
        long t1=test( entries, new HashMap() );
        long t2=test( entries, new ConcurrentHashMap() );

        long diff = (t2-t1)*100/(t1-t0);
        System.out.printf("entries=%,d time diff= %d%% %n", entries, diff);
    }
}


static long test(int ENTRIES, Map map)
{
    long SEED = 0;
    Random random = new Random(SEED);

    int RW_RATIO = 10;

    long t0 = System.nanoTime();

    for(int i=0; i<ENTRIES; i++)
        map.put( random.nextInt(), random.nextInt() );

    for(int i=0; i<RW_RATIO; i++)
    {
        random.setSeed(SEED);
        for(int j=0; j<ENTRIES; j++)
        {
            map.get( random.nextInt() );
            random.nextInt();
        }
    }
    long t = System.nanoTime()-t0;
    System.out.printf("%,d ns %s %n", t, map.getClass());
    return t;
}


static class FakeMap implements Map
{
    public Object get(Object key)
    {
        return null;  
    }
    public Object put(Object key, Object value)
    {
        return null;  
    }
    // etc. etc.
}
Run Code Online (Sandbox Code Playgroud)

  • HashMap 速度较慢的原因是它必须检测 ConcurrentModification 以了解何时抛出异常。ConcurrentHashMap 不必跟踪修改和检查 modCount。阅读您的收藏类的来源。 (2认同)

Aja*_*jax 7

HashMap可能更慢的原因是因为它必须检测ConcurrentModification以知道何时抛出异常.ConcurrentHashMap不必检查modCount以知道何时抛出(但它确实将它用于size()和isEmpty()).获取锁是非常快的,尤其是在单线程情况下,当你已经持有锁时,但是检查modCount是两次读取和跳转 - 如果不相等HashMap必须支付以抛出CoModException.

我建议您阅读集合类的源代码,以便了解在进行方法调用时他们正在做多少工作.在只有字典获取/放置的完全私有映射的情况下,您通常可以使用剥离的HashMap而不使用任何modCount或甚至大小跟踪来提高性能.


Ste*_*n C 6

这是一种很难以某种方式证明的橡胶声明.你如何衡量"几乎所有情况"

A ConcurrentHashMap可能比同步更好HashMap.争论越多,差异就越显着.另一方面,由于在后一种情况下不必要的锁定的开销,非同步HashMap可能比a更快ConcurrentHashMap.


我也希望看到该陈述的背景,以及该书作者提出的支持它的证据.并且有关未使用的假设的证据表明哈希映射的"几乎所有"用例都涉及同步.