首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么ConcurrentHashMap不能为每个桶设置一个锁?

为什么ConcurrentHashMap不能为每个桶设置一个锁?
EN

Stack Overflow用户
提问于 2014-08-20 17:35:37
回答 3查看 3.6K关注 0票数 19

如我们所知,java的ConcurrentHashMap有许多内部锁,每个锁都保护桶数组的某些区域。

一个问题是:为什么我们不能为每个桶创建一个锁

一个类似的问题已经被问到了:在Java ConcurrentHashMap中增加分区数量的缺点?

根据答案,有几个原因:

  1. 同时运行的最大线程数受处理器核心数的限制。是正确的吗?我们可以一直声明,如果我们有8核处理器,那么在ConcurrentHashMap?中不需要超过8个锁定区域。
  2. 浪费了L2缓存。为什么?
  3. 这是在浪费记忆。看起来这是因为额外的锁创建。

还有其他原因吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-08-21 16:44:57

我们能否始终声明,如果我们有8核处理器,我们不需要超过8个锁定的区域在ConcurrentHashMap?

不,这完全是错误的。这取决于两个因素,线程数(并发性)和段碰撞数。如果两个线程竞争同一段,一个线程可能会阻塞另一个线程。

虽然您只能拥有与内核相同的内核线程,但上面的语句的一个大错误是假设没有运行在核心上的线程不能拥有锁。但是拥有锁的线程仍然可以为下一个线程松开任务开关上的CPU,而下一个线程在试图获取相同的锁时会被阻塞。

但是,将线程数量调整为内核数量并不少见,特别是对于计算紧张的任务。因此,ConcurrentHashMap的并发级别间接地取决于典型设置中的核数。

为每个桶拥有一个锁将意味着维护一个锁状态和每个桶的等待队列,这意味着有相当多的资源。请记住,锁只需要并发写入操作,而不需要读取线程。

但是,对于Java 8实现来说,这种考虑是过时的。它使用了一种无等待更新的算法,至少对于没有冲突的桶。这有点像每个桶都有一个锁,因为运行在不同桶上的线程不互相干扰,但是没有维护锁状态的开销&等待队列。唯一需要关心的是给地图一个适当的初始大小。因此,如果指定了concurrencyLevel,则将其用作初始大小调整提示,但否则将忽略此提示。

票数 4
EN

Stack Overflow用户

发布于 2014-08-20 21:34:38

希望我能好好解释一下..。现在有点匆忙..。

你第一个问题的答案是:

“为什么我们不能为每个水桶创建一个锁?”

就是你可以为每个水桶创建一个锁--这并不一定是最好的行动方式。

你的问题的答案是:

我们能否始终声明,如果我们有8核处理器,我们就不需要超过8个锁定的ConcurrentHashMap区域

严格来说是“不”,尽管这取决于你所说的“需要”是什么意思。拥有多个与系统最大并发性相匹配或稍微更大的区域并不一定会防止争用,但实际上它运行得很好。没有什么可以阻止两个线程同时访问同一个区域,即使还有其他区域没有被锁定。

通过在一个8核处理器上拥有8个或更多的区域,您可以保证所有区域都可以同时访问,而不存在争用。如果你有8个核心(不是超线程),你最多可以同时执行8个操作。即使这样,理想的区域数目可能比核心的数目更多(例如,16),因为它将使争用以低成本(仅增加8个锁)的可能性降低。

拥有额外区域的好处最终会随着区域数量相对于最大并发性的增加而减少,这将导致它们浪费空间(内存),就像JavaDoc中提到的那样。这是在争用的可能性(给定一个区域的锁,另一个线程尝试访问它的概率)和浪费空间之间的平衡。

还有几个其他因素会影响ConcurrentHashMap的性能

  • 锁定代码的执行时间--这是一种很好的做法,使锁定的代码部分变得很小,以便它们能够快速完成并释放它们的锁。锁释放得越快,解决争用的速度就越快。
  • 数据分布--在高并发性下,分布良好的数据表现更好。将所有数据聚集在一个区域内意味着您将始终遇到争用。
  • 数据访问模式--同时访问不同区域的数据将表现得更好,因为您的线程不会争夺资源锁。如果您一次只访问一个区域,那么拥有分布良好的数据并不重要。

无论有多少个区域,所有这三件事都会对业绩产生积极或消极的影响,并会使区域数目减少。因为他们发挥了很大的作用,他们使它不太可能有更多的地区,将帮助你的整体。因为您只能同时执行这么多线程,所以让线程快速完成它们的工作并释放它们的锁是一个更好的焦点。

至于你关于缓存的问题:我真的不确定,但我可以猜测一下。当您大量使用映射时,这些锁将结束在缓存中,占用空间,可能会弹出其他可能更有用的东西。高速缓存比主存少得多,而缓存错过则浪费了很多时间。我认为这里的想法是一种普遍的厌恶,把很多东西放在缓存中,但并没有带来很大的好处。到了极致:如果缓存中充满了锁(不知怎么的),并且每个数据调用都被释放到内存中,那么性能就会受到影响。

票数 5
EN

Stack Overflow用户

发布于 2020-07-15 22:02:57

Java 8的ConcurrentHashMap确实在每个桶上设置了一个锁。写上了锁,但是并发读取也可能发生。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25411087

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档