希望我在解释方面做得很好...此刻有点匆忙...
第一个问题的答案:
“为什么我们不能为每个桶创建一个锁?”
您可以为每个存储桶创建一个锁 - 它不一定是最好的行动方案。
您问题的答案:
“我们是否可以始终声明,如果我们有8核处理器,我们在ConcurrentHashMap中不需要超过8个锁定区域”
从技术上讲是“不”,尽管这取决于你所说的“需要”是什么意思。拥有多个与系统的最大并发性匹配或稍大的区域并不一定能防止争用,但在实践中,它运行良好。没有什么可以阻止两个线程同时尝试访问同一区域,即使有其他区域未锁定也是如此。
通过在 8 核处理器上拥有 8 个或更多区域,可以保证的是,可以同时访问所有区域而不会发生争用。如果您有 8 个内核(不是超线程),则最多可以同时执行 8 个操作。即便如此,理想的区域数可能多(例如,16 个)多于内核数,因为这将使争用的可能性降低,而且成本较低(只有 8 个额外的锁)。
拥有额外区域的好处最终会随着区域数量相对于最大并发性的增加而减少,这导致它们浪费空间(内存),如 JavaDoc 中所述。这是争用的可能性(假设一个区域有锁,另一个线程尝试访问它的概率是多少)和浪费空间之间的平衡。
还有其他几个因素会影响性能:ConcurrentHashMap
-
锁定代码的执行时间 - 最好使锁定的代码段变小,以便它们快速完成并释放锁。释放锁的速度越快,解决争用的速度就越快。
- 数据分布 - 在高并发性下,分布良好的数据往往表现更好。将所有数据聚类在单个区域中意味着您将始终遇到争用。
- 数据访问模式 - 同时访问不同的数据区域将执行更好的操作,因为线程不会争用资源锁。如果一次只尝试访问一个区域,则拥有分布良好的数据并不重要。
无论有多少个区域,所有这三件事都会对性能产生积极或消极的影响,并可能使区域数量变得不那么相关。由于它们发挥了很大的作用,因此它们不太可能拥有更多的区域来帮助您。由于您只能同时执行这么多线程,因此拥有快速完成工作并释放其锁的线程是更好的焦点。
至于你关于缓存的问题:老实说我不确定,但我可以猜测。当您大量使用地图时,这些锁最终会在缓存上并占用空间,可能会碰出其他可能更有用的东西。缓存比主内存稀缺得多,缓存未命中会浪费大量时间。我认为这里的想法是普遍厌恶在缓存上放很多东西,这些东西并没有带来显着的好处。极端地说:如果缓存中充满了锁(以某种方式),并且每个数据调用都进入内存,那么性能就会受到影响。