我刚刚读了“干净的代码”这本书,偶然发现了这样一句话:
在Java很小的时候,Doug Lea就用Java语言编写了开创性的book8并发编程。除了这本书,他还开发了几个线程安全的集合,这些集合后来成为
java.util.concurrent
包中JDK的一部分。该包中的集合对于多线程情况是安全的,并且它们执行得很好。事实上,ConcurrentHashMap
实现在几乎所有情况下都比HashMap在中执行得更好。它还允许并发读取和写入,并且它具有支持通用复合操作的方法,否则这些复合操作就不是线程安全的。如果Java5是部署环境,则从ConcurrentHashMap
开始
请注意,在上面的引用中,我使用了"n",其中n是某个数字,以指示作者提供参考的地方,正如您可以看到的那样,他没有为粗体部分提供任何参考。
并不是我不相信这一说法,但我很想知道这一说法的支持证据。那么,有没有人知道可以同时显示ConcurrentHashMap
和HashMap
性能统计信息的资源?或者有人能给我解释一下为什么ConcurrentHashMap比HashMap快?
我可能会在休息的时候研究一下ConcurrentHashMap在工作中的实现,但现在我希望从SOers同事那里听到答案。
发布于 2011-07-15 05:17:16
Doug Lea非常擅长这些事情,所以如果有一次他的ConcurrentHashMap
比Joshua Bloch的HashMap
表现更好,我也不会感到惊讶。然而,从Java7开始,HashMap
的第一个@作者也变成了Doug Lea。显然,现在HashMap
没有理由比它的并发表亲慢。
出于好奇,我还是做了一些基准测试。我在Java7下运行,条目越多,性能越接近。最终,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.
}
发布于 2011-07-14 19:02:58
如果你只用一个线程访问HashMap,HashMap是最快的(它不做任何同步),如果你从多个线程访问它,ConcurrentHashMap比手工进行粗粒度的同步要快。这里有一个小小的比较:
发布于 2013-04-19 15:08:36
HashMap可能较慢的原因是因为它必须检测ConcurrentModification才能知道何时抛出异常。ConcurrentHashMap不需要检查modCount就能知道什么时候抛出(但它确实将它用于size()和isEmpty())。获取锁是非常快的,特别是在单线程的情况下,当您已经持有锁,但检查modCount是两次读取和一个跳转,如果不等于,HashMap必须支付抛出CoModException。
我建议您阅读您的集合类的源代码,这样您就可以在进行方法调用时知道它们正在做多少工作。当你只有一个完全私有的map用于字典get/put的时候,你通常可以使用一个没有任何modCount甚至大小跟踪的精简的HashMap来提升性能。
https://stackoverflow.com/questions/6692008
复制相似问题