并发哈希映射读写锁

我试图找到这些问题的答案,但无法在Google或Java文档中找到它。

情况 1:在 中,假设一个线程 t1 正在从段 n 读取,并且在同一个线程 t2 上写入同一段 nConcurrentHashMap

问题1:这两个操作是一个接一个地执行,还是同时执行?


情况 2:在 中,假设一个线程 t1 正在写入段 n,并且在同一个线程 t2 上想要从同一段 n 读取,ConcurrentHashMap

问题2:这两个操作是一个接一个,还是同时执行?


答案 1

我认为javadoc回答了你的两个问题:

检索操作(包括get)一般不阻塞,因此可能与更新操作(包括放置和删除)重叠。检索反映最近完成的更新操作在其开始时保持的结果。对于聚合操作(如 putAll 和 clear),并发检索可能仅反映插入或删除某些条目。

分段用于更新操作:

更新操作之间允许的并发性由可选的并发级别构造函数参数(默认值 16)指导,该参数用作内部大小的提示。

因此,简而言之,读取不会被阻止(它被实现为读取易失性变量)。如果写入在同一段中,则写入可能会相互阻止。


答案 2

根据 ConcurrentHashMap Oracle 文档,

ConcurrentHashMap的构造函数如下所示:

public ConcurrentHashMap (int initialCapacity, float loadFactor, int concurrencyLevel)

因此,上面的行将创建一个具有指定初始容量、负载因子和并发级别的新的空映射。其中,ConcurrentHashMap 构造函数中要考虑的重要参数:

  • 初始容量 - 初始容量。该实现执行内部大小调整以适应这么多元素。
  • 并发级别 - 估计的并发更新线程数。该实现执行内部大小调整以尝试容纳如此多的线程。

在 ConcurrentHashMap Api 中,您将找到以下常量。

  • 静态最终整数 DEFAULT_INITIAL_CAPACITY = 16;
  • 静态最终整数 DEFAULT_CONCURRENCY_LEVEL = 16;

默认情况下,ConcurrentHashMap 构造函数(或 Object)的初始容量参数和并发级别参数设置为 16。

因此,ConcurrentHashMap 默认维护一个包含 16 个锁的列表(锁数等于初始容量,默认情况下为 16 个),每个锁用于锁定 Map 的单个存储桶。这表示 16 个线程(线程数等于并发级别,默认情况下为 16 个)可以同时修改集合, 给定,每个线程在不同的存储桶上工作。因此,与哈希表不同,我们执行任何类型的操作(更新,删除,读取,创建),而无需锁定CurrentHashMap中的整个地图。

检索操作(包括 get)通常不会阻塞。在这种情况下,它使用易失性的概念,因此可能与更新操作(包括放置和删除)重叠。检索反映最近完成的更新操作在其开始时保持的结果。

更新操作之间允许的并发性由可选的并发级别构造函数参数(默认值 16)指导,该参数用作内部大小的提示。该表在内部分区,以尝试允许指定数量的并发更新而不会发生争用。由于哈希表中的位置基本上是随机的,因此实际并发性会有所不同。理想情况下,您应该选择一个值来容纳尽可能多的线程,以同时修改表。使用明显高于所需值的值会浪费空间和时间,而明显较低的值可能会导致线程争用。

我希望它有帮助!