Java: ConcurrencyLevel value for ConcurrentHashMap



ConcurrencyLevel是否存在某个最佳值,超过该值ConcurrentHashMap的性能会开始下降?

如果是,该值是多少?性能下降的原因是什么?(这个问题源于试图找出ConcurrentHashMap可能具有的任何实际限制)。

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

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

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

综上所述:最佳值取决于预期并发更新的数量一个数量级内的值应该很有效。超出该范围的值可能会导致性能下降。

你必须问自己两个问题

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

第一个问题告诉您一次可以访问映射的最大线程数。你可以有10000个线程,但如果你只有4个cpu,最多4个线程同时运行。

第二个问题告诉您,这些线程中访问映射并执行有用操作的线程最多。你可以优化地图来做一些无用的事情(例如,微基准),但对这个IMHO没有任何意义的调整。假设你有一个有用的程序,它经常使用地图。它可能会花90%的时间做其他事情,例如IO、访问其他映射、构建键或值、用从映射中获得的值做一些事情。

假设你花了10%的时间在一台有4个CPU的机器上访问地图。这意味着您平均将在0.4个线程中访问映射。(或者大约40%的时间是一个线程)在这种情况下,1-4的并发级别是可以的。

在任何情况下,使并发级别高于您拥有的cpu数量都可能是不必要的,即使对于微基准测试也是如此。

从Java 8开始,ConcurrentHashMapconcurrencyLevel构造函数参数实际上是未使用的,并且主要保持向后兼容性。该实现被重写为使用每个哈希bin中的第一个节点作为该bin的锁,而不是像早期版本中那样使用固定数量的段/条带。

简言之,从Java8开始,不必担心设置concurrencyLevel参数,只要根据API契约设置一个正(非零,非负)值即可。

相关内容

  • 没有找到相关文章

最新更新