Java:ConcurrentHashMap的ConcurrencyLevel值

时间:2012-02-27 13:15:19

标签: java concurrent-programming

ConcurrencyLevel是否有一些最佳值,超过该值,ConcurrentHashMap的性能开始降低?

如果是,那该值是什么,以及性能下降的原因是什么? (这个问题来自试图找出ConcurrentHashMap可能存在的任何实际限制)。

3 个答案:

答案 0 :(得分:4)

Javadoc提供了非常详细的指导:

  

更新操作之间允许的并发性由可选的concurrencyLevel构造函数参数(默认值为16)引导,该参数用作内部大小调整的提示。

     

该表在内部进行分区,以尝试允许指定数量的并发更新而不会发生争用。因为散列表中的放置基本上是随机的,所以实际的并发性会有所不同。理想情况下,您应该选择一个值来容纳与同时修改表一样多的线程。使用比您需要的更高的值会浪费空间和时间,而显着更低的值可能导致线程争用。但是,在一个数量级内过高估计和低估通常不会产生明显的影响。当知道只有一个线程会修改而其他所有线程只能读取时,值为1是合适的。

总结:最佳值取决于预期的并发更新数量。一个数量级内的值应该可以正常工作。超出该范围的值可能会导致性能下降。

答案 1 :(得分:4)

你必须问自己两个问题

  • 我有多少cpus?
  • 有用的程序访问同一地图的时间百分比是多少?

第一个问题告诉您一次可以访问地图的最大线程数。你可以有10000个线程,但是如果你只有4个cpus,最多只能运行4个。

第二个问题告诉你,这些线程中的任何一个都将访问地图并做一些有用的事情。您可以优化地图以执行无用的操作(例如微基准测试),但对此IMHO没有任何调整。假设您有一个有用的程序,它使用了很多地图。它可能花90%的时间做其他事情,例如IO,访问其他地图,构建键或值,使用从地图获取的值执行某些操作。

假设您花费10%的时间在具有4个CPU的计算机上访问地图。这意味着平均而言,您将平均访问0.4个线程的地图。 (或者大约40%的时间使用一个线程)在这种情况下,1-4的并发级别就可以了。

在任何情况下,即使对于微基准测试,也可能不需要使并发级别高于cpus的数量。

答案 2 :(得分:1)

从Java 8开始,ConcurrentHashMap的{​​{1}}构造函数参数为effectively unused,主要用于向后兼容。重新编写实现以使用每个哈希箱中的第一个节点作为该bin的锁,而不是像早期版本中那样固定数量的段/条带。

简而言之,从Java 8开始,只要根据API合约设置正(非零,非负)值,就不必担心设置concurrencyLevel参数。