ConcurrentHashMap构造函数参数?

我想知道构造ConcurrentHashMap的参数:

  • initialCapacity默认为16(理解)。
  • loadFactor默认为0.75。
  • concurrencyLevel默认为16。

我的问题是:

  • 应该使用什么标准来调整loadFactor上升或下降?
  • 我们如何建立并发更新线程的数量?
  • 应该使用什么标准来调整concurrencyLevel向上或向下?

另外:

  • 良好的哈希码实现的标志是什么? (如果SO问题解决了这个问题,请链接到它。)

谢谢!

简短的回答:将“初始容量”设置为大致预期在地图中放置的映射数量,并将其他参数保留为默认值。

答案很长:

  • 载荷系数是地图中“桶”数与预期元素数之间的比率;

  • 0.75通常是一个合理的折衷 – 我记得,这意味着有了一个好的哈希函数,平均而言我们期望大约1.6个重定向来在地图中找到一个元素(或者在该图周围);

    • 改变负载因子会改变更多重定向之间的折衷,以找到一个元素,但浪费的空间更少 – 把0.75真的通常是一个很好的值;

    • 原则上,将ConcurrencyLevel设置为您希望修改地图的并发线程数,尽管高估这个并不会产生不好的影响,而不是浪费内存(我前几刻写了一些关于ConcurrentHashMap性能的文章,以防万一)感兴趣)

非正式地,您的散列函数应该基本上旨在尽可能多地在位中“随机”。 或者更严格地说,给定元素的哈希码应该给每个位大约50%的机会设置。 实际上用一个例子来说明这一点实际上更容易:同样,你可能会对我写的有关String散列函数如何工作以及相关散列函数指南的一些内容感兴趣。 对这些东西的反馈是显而易见的欢迎。

我在某些方面也提到的一件事是你在实践中不必过于偏执:如果你的哈希函数在某些位中产生“合理”的随机性,那么它通常就可以了。 在最坏的情况下,将代表性的数据片段粘贴到字符串中并获取字符串的哈希码实际上并不是那么糟糕。

负载因子主要与散列函数的质量有关。 负载因子越接近零,即使散列函数不那么大,碰撞的可能性也越小。 权衡是内存占用更大。 换句话说,HashMap不是为每个单独的哈希码在单独的桶中分配条目,而是按接近度对它们进行分组,因此它拥有的桶越多,分布越分散,冲突的可能性就越小。

因此,根据您的需求和您在地图中存储的对象,您可以根据负载因素来改善查找时间或减少内存。

ConcurrencyLevel实际上取决于您的应用程序。 如果您只在应用程序中运行了两个或三个线程,那么就去了。 如果您是具有任意数量线程的应用程序服务器,那么您需要了解您的负载容量以及要优化的点。

优质的哈希码实现在最少的冲突数量的同时提供尽可能广泛的对象潜在值的分布,同时遵守合同。 换句话说,它允许HashMap(或者视情况而定)将对象分配到单独的桶中,​​从而使查找更快。

loadFactor:控制实现何时决定调整哈希表的大小。 价值太高会浪费空间; 太低的值将导致昂贵的resize操作。

concurrencyLevel:告诉实现尝试针对给定数量的写入线程进行优化。 根据API文档,最多关闭10倍不应该对性能产生太大影响。

更新操作之间允许的并发性由可选的concurrencyLevel构造函数参数(缺省值16)引导,该参数用作内部大小调整的提示。 该表在内部进行分区,以尝试允许指定数量的并发更新而不会发生争用。 因为散列表中的放置基本上是随机的,所以实际的并发性会有所不同。 理想情况下,您应该选择一个值来容纳与同时修改表一样多的线程。 使用比您需要的更高的值会浪费空间和时间,而显着更低的值可能导致线程争用。 但是,在一个数量级内过高估计和低估通常不会产生明显的影响。

良好的哈希码实现将在任何间隔上均匀地分布哈希值。 如果事先知道了密钥集,则可以定义“完美”散列函数,该函数为每个密钥创建唯一的散列值。

loadFactor默认设置为0.75,应该使用什么标准来调整此值?

在了解哈希映射的工作原理之前,您需要了解哈希映射的工作背景。 该地图基本上是一系列的桶。 地图中的每个值都会根据其哈希码的内容放入存储桶中。 loadFactor意味着,如果存储桶超过75%,则应调整Map的大小

concurrencyLevel默认设置为16,我们如何建立并发更新线程的数量? 应该使用什么标准来调整此值?

这是在询问您期望多少线程同时修改Map(同时)

有关哈希码,请参阅Joshua Bloch的Effective Java