Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么ConcurrentHashMap不能为每个bucket设置锁?_Java_Multithreading_Concurrency_Concurrenthashmap - Fatal编程技术网

Java 为什么ConcurrentHashMap不能为每个bucket设置锁?

Java 为什么ConcurrentHashMap不能为每个bucket设置锁?,java,multithreading,concurrency,concurrenthashmap,Java,Multithreading,Concurrency,Concurrenthashmap,我们知道,java的ConcurrentHashMap有许多内部锁,每个锁都保护bucket数组的某个区域 一个问题是:为什么我们不能为每个bucket创建一个锁 已经提出了一个类似的问题: 根据答案,有几个原因: 同时运行的最大线程数受处理器内核数的限制这是否正确?我们是否可以始终声明,如果我们有8核处理器,那么ConcurrentHashMap中不需要超过8个锁定区域? 存在二级缓存的浪费为什么? 这是对记忆的浪费。看起来这是因为额外的锁创建 还有其他原因吗?希望我能很好地解释一下。。。现在

我们知道,java的ConcurrentHashMap有许多内部锁,每个锁都保护bucket数组的某个区域

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

已经提出了一个类似的问题:

根据答案,有几个原因:

  • 同时运行的最大线程数受处理器内核数的限制这是否正确?我们是否可以始终声明,如果我们有8核处理器,那么ConcurrentHashMap中不需要超过8个锁定区域?

  • 存在二级缓存的浪费为什么?

  • 这是对记忆的浪费。看起来这是因为额外的锁创建


  • 还有其他原因吗?

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

    第一个问题的答案是:

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

    你可以为每个bucket创建一个锁——这不一定是最好的做法

    你的问题的答案是:

    “我们是否可以始终声明,如果我们有8核处理器,那么ConcurrentHashMap中不需要超过8个锁定区域?”

    从技术上讲是“不”,尽管这取决于你所说的“需要”是什么意思。拥有多个与系统最大并发性相匹配或略大的区域并不一定能防止争用,但在实践中效果很好。没有什么可以阻止两个线程同时尝试访问同一个区域,即使还有其他未锁定的区域

    通过在8核处理器上安装8个或更多区域,您可以保证所有区域都可以同时访问,而不会发生争用。如果您有8个内核(非超线程),则最多可以同时执行8个操作。即使这样,理想的区域数也可能比核心数更多(比如说,16个),因为这将以较低的成本降低争用的可能性(仅增加8个锁)

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

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

    • 锁定代码的执行时间-最好将锁定的代码段变小,以便它们快速完成并释放锁。锁释放得越快,争用问题解决得越快
    • 数据分布—良好分布的数据在高并发性下往往表现得更好。将所有数据聚集在单个区域内意味着您将始终遇到争用
    • 数据访问模式-同时访问不同区域的数据会更好,因为线程不会争夺资源锁。如果您一次只尝试访问一个区域,那么拥有分布良好的数据并不重要
    无论有多少地区,这三个因素都会对绩效产生积极或消极的影响,并且会降低地区数量的相关性。因为他们扮演了一个重要的角色,所以他们不太可能有更多的地区来帮助你。由于您只能同时执行这么多线程,因此让线程快速完成工作并释放锁是一个更好的关注点

    至于你关于缓存的问题:老实说,我不确定,但我可以猜一猜。当您大量使用地图时,这些锁最终会出现在缓存上并占用空间,可能会破坏其他更有用的东西。缓存比主内存少得多,缓存未命中会浪费大量时间。我认为这里的想法是一个普遍的厌恶把很多东西放在缓存中,而这些东西并没有提供显著的好处。极端情况:如果缓存中(不知何故)充满了锁,并且每个数据调用都被释放到内存中,那么性能就会受到影响

    我们是否可以始终声明,如果我们有8核处理器,那么ConcurrentHashMap中不需要超过8个锁定区域

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

    虽然拥有核心的线程数量与拥有核心的线程数量相同,但上述语句的最大错误是假设不在核心上运行的线程不能拥有锁。但是,拥有锁的线程仍然可能会松开下一个线程的任务开关上的CPU,而下一个线程在尝试获取相同的锁时会被阻塞

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


    为每个bucket设置一个锁意味着为每个bucket维护一个锁状态和一个等待队列,这意味着相当多的资源。请记住,锁仅用于并发写入操作,而不用于读取线程

    然而,对于Java8实现来说,这种考虑已经过时了。它对bucket更新使用无等待算法,至少对没有冲突的bucket是这样。这有点像每个bucket都有一个锁,因为在不同bucket上运行的线程不会相互干扰,但没有维护锁状态和等待队列的开销。唯一需要关心的是给地图一个批准