ConcurrencyLevel 是否存在某个最佳值,超过该值 ConcurrentHashMap 的性能开始下降?
如果是,该值是多少,性能下降的原因是什么?(这个问题源于试图找出 ConcurrentHashMap 可能具有的任何实际限制)。
ConcurrencyLevel 是否存在某个最佳值,超过该值 ConcurrentHashMap 的性能开始下降?
如果是,该值是多少,性能下降的原因是什么?(这个问题源于试图找出 ConcurrentHashMap 可能具有的任何实际限制)。
Javadoc提供了非常详细的指导:
更新操作之间允许的并发性由可选的
concurrencyLevel
构造函数参数(默认为 16)指导,该参数用作内部大小调整的提示。该表在内部进行了分区,以尝试允许指定数量的并发更新而不会发生争用。因为哈希表中的放置本质上是随机的,所以实际的并发性会有所不同。理想情况下,您应该选择一个值来容纳尽可能多的线程同时修改表。使用显着高于您需要的值会浪费空间和时间,而显着降低的值会导致线程争用。但是一个数量级内的高估和低估通常不会产生太大的影响。当已知只有一个线程会修改而所有其他线程只会读取时,值 1 是合适的。
总结一下:最佳值取决于预期的并发更新数。一个数量级内的值应该可以很好地工作。超出该范围的值可能会导致性能下降。
你必须问自己两个问题
第一个问题告诉您一次可以访问映射的最大线程数。您可以拥有 10000 个线程,但如果您只有 4 个 cpu,则最多同时运行 4 个。
第二个问题告诉您,这些线程中的大多数都将访问地图并做一些有用的事情。您可以优化地图以做一些无用的事情(例如微基准),但恕我直言,调整没有意义。假设您有一个有用的程序,它经常使用地图。它可能会花费 90% 的时间做其他事情,例如 IO、访问其他地图、构建键或值、使用从地图中获得的值做一些事情。
假设您花费 10% 的时间在具有 4 个 CPU 的机器上访问地图。这意味着平均而言,您将在 0.4 个线程中访问地图。(或者一个线程大约 40% 的时间)在这种情况下,1-4 的并发级别就可以了。
在任何情况下,使并发级别高于您拥有的 cpu 数量可能是不必要的,即使对于微基准测试也是如此。
从 Java 8 开始,ConcurrentHashMap
for 的构造函数参数实际上concurrencyLevel
是未使用的,主要是为了向后兼容。该实现被重新编写,以使用每个哈希箱中的第一个节点作为该箱的锁,而不是像早期版本中那样使用固定数量的段/条带。
简而言之,从 Java 8 开始,不必担心设置concurrencyLevel
参数,只要根据 API 合约设置一个正(非零、非负)值即可。