4

我正在阅读ConcurrentHashMap这个相关的教程,并且有一些问题。

  1. 在文章中,提到了ConcurrentHashMap允许多个阅读器同时阅读而没有任何阻塞。这是通过根据并发级别将 Map 划分为不同的部分并在更新期间仅锁定 Map 的一部分来实现的。默认并发级别为 16,因此 Map 分为 16 个部分,每个部分由不同的锁管理。这意味着,16 个线程可以同时对 Map 进行操作,直到它们对 Map 的不同部分进行操作。尽管ConcurrentHashMap保持线程安全完好无损,但这仍然具有高性能。不过,它有一个警告:由于更新操作,如put()remove()putAll()clear()不同步,并发检索可能不会反映 Map 上的最新更改

  2. 文章中还提到了另一点:另一个要记住的重要一点是 CHM 上的迭代,返回的迭代器keySet是弱一致的,它们只反映ConcurrentHashMap某一点的状态,可能不反映任何最近的变化

我没有理解以粗体突出显示的要点,您能否提供更多信息或在一个简单的程序中向我展示?

4

2 回答 2

2
  1. 由于 put()、remove()、putAll() 或 clear() 等更新操作不同步,并发检索可能无法反映 Map 上的最新更改

    据我了解,这意味着在一个线程中对地图的修改可能不一定会在另一个线程中同时发生的检索中看到。考虑以下示例:

                      Thread 1 starts              Thread 1's call to get("a")
                     a call to get("a")             completes, returning null
                             |                                 |
    Thread 1        ---------+---------------------------------+-------
                                 time ----->
    Thread 2        -----+---------------------------+-----------------
                         |                           |
                 Thread 2 starts a            Thread 2's call to
                call to put("a", 1)          put("a", 1) completes
    

    即使线程 2put在映射线程 1get完成执行中的值,线程 1 也没有“看到”映射修改,并返回了null.

  2. 另一个需要记住的重点是 CHM 上的迭代,ConcurrentHashMap 的 keySet 返回的迭代器是每周一致的,它们只反映 ConcurrentHashMap 的状态和某个点,可能不会反映任何最近的变化。

    这是一个类似的情况。如果线程 1Iterator从 aConcurrentHashMap获得an keySet,然后线程 2 将新条目放入映射中,Iterator则线程 1 不能保证看到该条目。(它可能会或可能不会。)

于 2013-02-27T17:49:44.013 回答
0

这里真正的问题是,当多个线程在使用数据结构时,线程不一定会步调一致。

一个线程正在为 user1 读取。一个线程正在为 user2 编写。两个线程都无法预测另一个线程在各自进程中的位置。此外,我们无法为用户预测这两个过程完成时的任何排序。如果写入首先更新数据,则读取将显示更新的状态,即使 user1 可能早一点请求读取。

迭代时的读取或修改工作方式相同,另外考虑到移动到下一个(迭代时)的过程本质上变成了对 Map 状态的“读取”操作,如果不是其中任何特定数据的内容的话.

因此,当您在这些数据结构中允许并发时,您最终会在时间上进行“足够接近”的测试。(这很像数据库的相同考虑,除了我们习惯于以这种方式考虑数据库并且时间框架是 10 个不同的几个因素。

注意:要对@Matts 在另一个答案中显示的精彩小时间线发表评论...

时间线显示两个线程以及每个线程的开始和停止。两个线程的开始可以按 (a,b) 或 (b,a) 顺序发生。结束可以按任意顺序发生,因为您无法判断操作需要多长时间。这给出了两个线程可以开始和结束的 4 种方式。(a 先开始然后结束,a 先开始,b 先结束,b 先开始,a 先结束,b 先开始,b 先结束)现在......想象一下 20 个线程都在做同样的事情来响应,比如说, 20 个最终用户为此和那个提交请求。它有多少种可能的方法。

于 2013-02-27T17:34:51.900 回答