如我们所知,java的ConcurrentHashMap有许多内部锁,每个锁都保护桶数组的某些区域。
一个问题是:为什么我们不能为每个桶创建一个锁
一个类似的问题已经被问到了:在Java ConcurrentHashMap中增加分区数量的缺点?
根据答案,有几个原因:
还有其他原因吗?
发布于 2014-08-21 16:44:57
我们能否始终声明,如果我们有8核处理器,我们不需要超过8个锁定的区域在ConcurrentHashMap?
不,这完全是错误的。这取决于两个因素,线程数(并发性)和段碰撞数。如果两个线程竞争同一段,一个线程可能会阻塞另一个线程。
虽然您只能拥有与内核相同的内核线程,但上面的语句的一个大错误是假设没有运行在核心上的线程不能拥有锁。但是拥有锁的线程仍然可以为下一个线程松开任务开关上的CPU,而下一个线程在试图获取相同的锁时会被阻塞。
但是,将线程数量调整为内核数量并不少见,特别是对于计算紧张的任务。因此,ConcurrentHashMap的并发级别间接地取决于典型设置中的核数。
为每个桶拥有一个锁将意味着维护一个锁状态和每个桶的等待队列,这意味着有相当多的资源。请记住,锁只需要并发写入操作,而不需要读取线程。
但是,对于Java 8实现来说,这种考虑是过时的。它使用了一种无等待更新的算法,至少对于没有冲突的桶。这有点像每个桶都有一个锁,因为运行在不同桶上的线程不互相干扰,但是没有维护锁状态的开销&等待队列。唯一需要关心的是给地图一个适当的初始大小。因此,如果指定了concurrencyLevel,则将其用作初始大小调整提示,但否则将忽略此提示。
发布于 2014-08-20 21:34:38
希望我能好好解释一下..。现在有点匆忙..。
你第一个问题的答案是:
“为什么我们不能为每个水桶创建一个锁?”
就是你可以为每个水桶创建一个锁--这并不一定是最好的行动方式。
你的问题的答案是:
我们能否始终声明,如果我们有8核处理器,我们就不需要超过8个锁定的ConcurrentHashMap区域
严格来说是“不”,尽管这取决于你所说的“需要”是什么意思。拥有多个与系统最大并发性相匹配或稍微更大的区域并不一定会防止争用,但实际上它运行得很好。没有什么可以阻止两个线程同时访问同一个区域,即使还有其他区域没有被锁定。
通过在一个8核处理器上拥有8个或更多的区域,您可以保证所有区域都可以同时访问,而不存在争用。如果你有8个核心(不是超线程),你最多可以同时执行8个操作。即使这样,理想的区域数目可能比核心的数目更多(例如,16),因为它将使争用以低成本(仅增加8个锁)的可能性降低。
拥有额外区域的好处最终会随着区域数量相对于最大并发性的增加而减少,这将导致它们浪费空间(内存),就像JavaDoc中提到的那样。这是在争用的可能性(给定一个区域的锁,另一个线程尝试访问它的概率)和浪费空间之间的平衡。
还有几个其他因素会影响ConcurrentHashMap的性能
无论有多少个区域,所有这三件事都会对业绩产生积极或消极的影响,并会使区域数目减少。因为他们发挥了很大的作用,他们使它不太可能有更多的地区,将帮助你的整体。因为您只能同时执行这么多线程,所以让线程快速完成它们的工作并释放它们的锁是一个更好的焦点。
至于你关于缓存的问题:我真的不确定,但我可以猜测一下。当您大量使用映射时,这些锁将结束在缓存中,占用空间,可能会弹出其他可能更有用的东西。高速缓存比主存少得多,而缓存错过则浪费了很多时间。我认为这里的想法是一种普遍的厌恶,把很多东西放在缓存中,但并没有带来很大的好处。到了极致:如果缓存中充满了锁(不知怎么的),并且每个数据调用都被释放到内存中,那么性能就会受到影响。
发布于 2020-07-15 22:02:57
Java 8的ConcurrentHashMap确实在每个桶上设置了一个锁。写上了锁,但是并发读取也可能发生。
https://stackoverflow.com/questions/25411087
复制相似问题