朋友您好我是Java Concurrency的新手。我有两个问题如下。
Q.1在ConcurrentHashMap中如何定义段?意味着如果Map中的64个元素和concurrencyLevel值为16(有16个线程可以同时工作)那么这些段是如何定义的?问题是它们是相同大小的16个段,每个段有4个元素吗?或者它将是不等大小的片段?
Q.2。如果我定义ConcurrentHashMap,初始容量为62,concurrencyLevel为16.如果我在该映射中放入62个元素。根据我的理解,将有15个段,每个段有4个元素,第16段有2个元素?我在这里纠正吗?
提前致谢
答案 0 :(得分:1)
考虑ConcurrentHashMap
的实现,它们使用段(不是全部),因为它基本上是一个两级哈希表。给定密钥K
和密钥h = K.hashCode()
的哈希码,您首先使用h
哈希到16个段的数组中,就像普通哈希映射一样(例如,通过{ {1}}或类似的东西)。这会为您提供密钥所在的细分,这只是另一个地图 - 再次使用h % 16
在此地图中查找密钥。
不同之处在于,任何锁定操作(通常在h
等变异操作期间发生)只需要锁定所涉及的段,因此其他操作有可能并行进行。
具体回答您的问题:
<强> Q1 强>
这些段的容量大小相同,但它们通常具有不等数量的元素,因为元素的段是使用散列选择的,除非在特殊情况下,否则不会导致完全均匀。它就像你询问put()
中支持的前半部分是否与后半部分具有相同数量的元素一样。在平均 期望的元素数量是相同的,但对于任何给定的HashMap
,它与完全高度不同>由于随机变化,两半中的元素数量相同。
<强> Q2 强>
不,地图不会像那样布局。如上所述,使用散列来完成将元素选择成片段,这意味着(对于良好的散列函数),片段基本上是随机选择的。想象一下,你有一个标记为1到16的球,你一次选择一个球,62次,并记录你在更换球之前得到的数字。你不会期望获得像HashMap
这样的发行版!它会更随机。
答案 1 :(得分:0)
Q.1在ConcurrentHashMap中如何定义段?意味着如果Map中的64个元素和concurrencyLevel值为16(有16个线程可以同时工作)那么这些段是如何定义的?问题是它们是相同大小的16个段,每个段有4个元素吗?或者它是不等大小的片段?
ANS - 如果您将16定义为并发级别,那么将创建16个分段。
每个段内部维护HashTable S [0] - &gt;哈希表()。
因此,如果您有64个元素,那么每个元素Hash(Key)将计算分段编号,您可能拥有所有不同大小的分段。段哈希码的计算方式是它将返回(0-15)之间的任何数字。
<强> Q.2。如果我定义ConcurrentHashMap,初始容量为62,concurrencyLevel为16.如果我在该映射中放入62个元素。根据我的理解,将有15个段,每个段有4个元素,第16段有2个元素?我在这里纠正吗?
ANS-如上所述,每个段的选择都是基于计算的哈希码完成的,因此不能确定所有16段都具有相同的大小。
答案 2 :(得分:0)
这里有一些计算逻辑,可以帮助您在构造ConcurrentHashMap时计算段的数目以及每个段中HashTable的大小。
如果并发级别为16,则预期的段数将不是-
2^n => concurrency level.
i.e 2^4 >= 16
16 => 16 Hence 16 segments will be created.
Similarly if concurrency level is 10 then
Segment array size would be 2^n => 10 i.e 2^4 => 10
Segment array size is 16
another example - if concurrency level is 8 then
segment size = 2^n => 8 i.e 2^3=> 8
hence segment size will be 8.
计算每个细分下的HashTable的大小-
HashEntry[] array size = 2 ^ x ≥ (initialCapacity / concurrencyLevel)
Example -
ConcurrentHashMap map = new ConcurrentHashMap(64, 0.75f, 8)
HashEntry[] array size = 2^n ≥ 64/8 => 2^3 ≥ 8
Hence, HashEntry[] array size will be 8.
Also Segment size will be = 2^n ≥ 8 => 8.