有人可以为以下问题提供答案:
我理解null
中不允许ConcurrentHashMap
值的原因。但是为什么不允许null
键?
并发级别确定可以并发访问映射的线程数,默认值为16.这意味着映射分为16个部分,并且每个部分都放置了锁。只要初始容量也是16,这样工作正常,因此有16个桶和16个锁,每个桶可以锁定一个锁。 当初始容量大于并发级别时以及初始容量小于并发级别时,它如何工作?
答案 0 :(得分:1)
null
个键? HashMap从Object.hash()
获取其内部键,无法为空值计算。为了解决这个问题,非并发HashMaps将null映射到哈希码0.为了在ConcurrentHashMap
中解决这个问题,应该可以牺牲性能。答案 1 :(得分:1)
[...]地图分为16个部分,并在每个部分上放置锁定。只要初始容量也是16,这样就可以正常工作,因此有16个桶和16个锁,每桶可以锁定一个锁。
为什么假设16个线程中的每一个都想要访问不同的存储桶?如果他们都想要访问相同的存储桶怎么办?
不要将其视为16个不同的存储桶,将其视为16个完全不同的子表。散列k.hashCode()
不仅确定密钥k
所属的表的哪个桶,还确定在哪个子表中。
如果两个线程对两个不相关的密钥j
和k
感兴趣,那么密钥属于不同子表的概率为15/16,并且线程可以访问表没有争用。另外1/16的时间,这是艰难的运气,其中一个线程将不得不等待;但这比他们100%碰撞的情况要好得多。
答案 2 :(得分:0)
问题1
我想一般来说支持null
密钥是可能的。但这会对可读性产生影响,并可能对性能产生一点影响。后者与提供高性能多线程地图实现的目标相冲突。
问题2 如果初始容量小于预期的并发级别,则将初始容量调整为访问Map(initialCapacity = concurrencyLevel
)的估计线程数。除此之外,对ConcurrentHashMap
的并发访问在很大程度上与容量无关,因为线程会在访问时锁定整个存储桶(更具体地说,它们会锁定存储桶中的第一个元素)。