【问题标题】:Modifying values in ConcurrentHashMap修改 ConcurrentHashMap 中的值
【发布时间】:2013-04-09 18:13:21
【问题描述】:

在 ConcurrentHashMap 中有分段的概念。如果两个线程试图访问 ConcurrentHashMap 意味着什么,它们被分成两个块,块的默认大小为 16。

现在假设 ConcurrentHashMap 只有两个元素,两个不同的线程来了,thread1 尝试修改第一个值,thread2 尝试修改第二个值。这种情况下ConcurrentHashMap会不会去切分?

现在在不同的情况下,两个线程都尝试修改相同的值 ConcurrentHashMap 将如何处理这种情况?通过使用锁定机制还是有别的东西?

【问题讨论】:

  • 您需要定义“修改一个值”。 hashmap 不太关心更改其值的属性,并且根本不与之交互,请显示示例代码。

标签: java java.util.concurrent concurrenthashmap


【解决方案1】:

ConcurrentHashMap 有几个桶。键根据其哈希值映射到其中一个桶中。当您添加或检索值时,与该键关联的存储桶被锁定。

对于您的第一个问题,有两种可能性:两个密钥位于同一个存储桶中,或者它们位于不同的存储桶中。在第一种情况下,一次只能有一个线程工作——第一个获得锁的线程将抓住它并工作,第二个线程将等待轮到它。在第二种情况下,密钥位于不同的桶中,它们将各自获取独立的锁并同时执行它们的工作。

对于第二个问题,bucket 被锁定,仅此而已。如果两个线程尝试为同一个键存储两个值,则 ConcurrentHashMap 承诺这两个值之一将与该键相关联。 如果线程 A 运行 map.put("Answers",2); 并且线程 B 运行 map.put("Answers",10);,则 ConcurrentHashMap 将确保映射有效并且包含 210 for "Answers",但它赢了不要对这两者中的哪一个做出任何承诺。

【讨论】:

  • 在java中;所有引用的分配都是atomic by nature. 所以如果两个线程试图改变同一个键的值;默认情况下这将是原子的吗?那为什么在这种情况下我们需要 CHM 或 Lock 呢?
  • 因为put 不仅仅是简单的赋值:它可能需要分配空间,并且它会保留一个计数器来记录它有多少条目。看一下代码(旧链接但仍然相关):grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
  • PlusOne!谢谢!明白了。
【解决方案2】:

CHM 保证这些操作(例如putputIfAbsent 等)不会重叠,是的,这是通过锁定完成的。 CHM 的每个段都有自己的锁,每当您修改该段时都会使用该锁。

(作为参考,正如@Affe 指出的那样,如果您正在修改ConcurrentHashMap 中值的内容,CHM 不会做--不能做-- 任何事情使该线程安全。)

【讨论】:

    【解决方案3】:

    首先,CHM 的新实现根本不使用 Segments,它仍然使用节点数组,如果给定索引中的节点不存在并且两个线程试图插入两个条目,其哈希码等于给定index 然后 CHM 使用 CAS ,否则如果节点存在,则 CHM 使用该节点的第一个元素上的锁定来放置新值。 CHM 中的读取是非阻塞的,并且在 Unsafe 类的原子读取的帮助下使用发生在保证之前。查看我关于 CHM 的博客了解更多详情 https://strogiyotec.github.io/pages/posts/chm.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-20
      • 1970-01-01
      • 1970-01-01
      • 2016-06-30
      • 2015-05-19
      • 1970-01-01
      相关资源
      最近更新 更多