Java ConcurrentHashMap中增加分区数的缺点?

时间:2013-06-21 11:16:37

标签: java data-structures concurrenthashmap

Java ConcurrentHashMap在内部维护分区。每个分区可以单独锁定。 可能存在多个线程访问的所有密钥落入同一分区并且分区可能没有帮助的情况。 进一步增加分区数应该可以提高并发性。

为什么Java将分区计数的默认值设置为16而不是非常高的值? 地图中有大量分区的表现是什么?

2 个答案:

答案 0 :(得分:6)

  

为什么Java将分区计数的默认值设置为16而不是非常高的值?

很少有同时使用相同CHM的这些CPU(线程数不是那么重要)。如果你真的需要这个,通常有一种更好的方法来编写应用程序,避免这种情况。

例如,假设您有1000个线程但只有8个CPU。这意味着假设您的程序没有做任何有用的事情,例如,最多只有8个线程将运行并访问CHM。别的什么。

在实际程序中,很少有一个集合的使用时间超过10%。这是因为通常涉及一些IO,或者重组线程以使用那里自己的集合副本并在最后收集它们是有意义的,例如地图,减少

  

Map中有大量分区的表现是什么?

你浪费了一些无关紧要的内存,但大多数时候你浪费了一些限制为32 KB的L1缓存和相对宝贵的资源。

答案 1 :(得分:2)

这是javadoc所说的(Java 6):

  

“更新操作之间允许的并发性由可选的concurrencyLevel构造函数参数(缺省值16)引导,该参数用作内部大小调整的提示。该表在内部分区以尝试允许指定的并发数量更新没有争用。因为哈希表中的位置基本上是随机的,实际的并发性会有所不同。理想情况下,你应该选择一个值来容纳与同时修改表一样多的线程。使用比你需要的值高得多的值会浪费空间时间和价值显着降低可能导致线程争用。但是在一个数量级内过高估计和低估通常不会产生明显的影响。当知道只有一个线程会修改而其他所有线程都被修改时,值为1是合适的。只会读取。另外,调整此或任何其他类型的哈希表是一个相对较慢的操作,因此,如果可能,提供e的估计是一个好主意构造函数中的xpected表大小。“

所以简短的回答是默认值(16)是限制并发和浪费空间之间的折衷。 “非常高”的价值会浪费很多空间。 (正如Peter Lawrey指出的那样,由于内存缓存效应会导致性能下降。)

需要注意的另一件事是,LinkedHashMap实现会默默地将concurrencyLevel的值限制为2 16 。 (至少,这就是Java 6代码所做的。)很难设想一个真实世界的场景,你需要那么多的并发。