【问题标题】:Is KeySet iterator of ConcurrentHashMap is threadsafe?ConcurrentHashMap 的 KeySet 迭代器是线程安全的吗?
【发布时间】:2013-10-25 08:04:52
【问题描述】:

我只是想探索一下ThreadSafe是什么意思?

以下是我的理解:

对我来说看起来像;允许多个线程同时访问一个集合;这与它的同步无关。例如任何没有同步关键字的方法;是线程安全的,意味着多个线程可以访问它。

开发人员可以选择在此方法上维护更多逻辑(同步),以在多线程访问数据时保持数据完整性。这与线程安全是分开的。

如果我的上述陈述是错误的;只需阅读下面的 JAVA DOC 即可了解 `ConcurrentHashMap:

keySet:视图的迭代器是一个“弱一致”的迭代器,永远不会抛出 ConcurrentModificationException,并保证遍历构造迭代器时存在的元素,并且可能(但不保证)反映构造后的任何修改。

上面的声明说keySet迭代器不会保证数据的完整性;而多线程正在修改集合。

你能回答我吗,*ConcurrentHashMap 的 KeySet 迭代器是线程安全的吗?

我对线程安全的理解是正确的??

【问题讨论】:

  • 你的问题本身就有答案。
  • 随着 javadoc 的发展,这非常清楚,没有答案可以更好或更清晰地解释它。你到底有什么不明白的?
  • ConcurrentHashMap keySet() 是线程安全的,因此可能不需要同步或复制。
  • “迭代器永远不会抛出 ConcurrentModificationException,并保证遍历在迭代器构造时存在的元素”——这足以使某些东西成为“线程安全”。问题是,您究竟将什么定义为“线程安全”...
  • @afk5min 引用的是您对线程安全的定义吗?所以这意味着线程安全不会确保对集合进行什么修改..只是允许多个线程能够遍历元素..?

标签: java multithreading


【解决方案1】:

keySet:视图的迭代器是一个“弱一致”的迭代器,它永远不会抛出 ConcurrentModificationException,并保证在构造迭代器时遍历元素,并且可以(但不保证)反映构造后的任何修改

这本身就说明,ConcurrentHashMap 的 KeySet 迭代器是线程安全的。

【讨论】:

  • 所以你的意思是线程安全在访问它时没有数据完整性/一致性......?
【解决方案2】:

java.util.concurrent 包背后的总体想法是提供一组数据结构,这些数据结构提供线程安全访问,但没有强一致性。通过这种方式,这些对象实现了比正确锁定对象更高的并发性。

线程安全意味着,即使没有任何显式同步,您也永远不会破坏对象。在HashTableHashMap 中,一些方法是多线程访问的潜在问题,例如remove 方法,它首先检查元素是否存在,然后将其删除。这些方法在ConcurrentHashMap 中被实现为原子操作,因此您不必担心会丢失一些数据。

但这并不意味着这个类对每个操作都自动锁定。 putAll 和迭代器等高级操作不同步。该类不提供强一致性。保证您的操作的顺序和时间不会损坏对象,但不能保证生成准确的结果。

例如,如果您在调用putAll 的同时打印对象,您可能会看到部分填充的输出。与新插入同时使用迭代器也可能不会反映您引用的所有插入。

这与线程安全不同。尽管结果可能会让您感到惊讶,但您可以放心,不会丢失或意外覆盖任何内容,元素可以毫无问题地添加到对象中或从对象中删除。如果此行为足以满足您的要求,建议您使用java.util.concurrent 类。如果您需要更高的一致性,那么您需要使用来自java.util 的同步类或自己使用同步。

【讨论】:

  • 很好的答案。大多数时候,绝对不需要“顺序化”(并发调用转换为任意顺序的顺序调用,synchronized & co.),也不需要“确定性顺序化”,其中并发调用转换为顺序调用特定的、可重复的顺序。这就是为什么“线程安全”具有完全不同的含义的原因。
【解决方案3】:

根据您的定义,ConcurrentHashMap.keySet() 返回的Set 线程安全的。

但是,正如您在引用中指出的那样,它可能会以非常奇怪的方式起作用。

  1. 作为Set,条目可能随机出现和/或消失。 IE。如果您对同一个对象调用两次contains,这两个结果可能会有所不同。
  2. 作为Iterable,您可以在两个不同的线程中开始其底层对象的两次迭代,并发现这两次迭代枚举了不同的条目。
  3. Furthermre、contains 和迭代也可能不匹配。

但是,如果您在持有 Set 时以某种方式锁定底层 Map 以防止修改,则不会发生此活动,但需要这样做并不意味着该结构不是线程安全的。

【讨论】:

  • 所以我可以看到很多使用迭代器的不一致;那为什么它被称为Threadsafe ...?或线程安全是否超出数据一致性..?
  • @KanagaveluSugumar - 线程安全意味着通过多个线程访问它不会中断或崩溃。如果你在乎的话,它可能会产生不一致的结果——你必须为自己辩护。 开发人员可以选择在此方法上维护更多逻辑(同步),以在多线程访问时保持数据完整性。
  • 噢噢噢噢..?是吗 ..?所以我的理解是正确的..?这个stackoverflow.com/questions/6324085/what-is-thread-safe-in-java 问题的最佳答案是错误的,是吗..?
  • @KanagaveluSugumar - 在我看来,线程安全意味着如果您在写入时不使用synchronized,则结构可能会损坏。这不需要线程之间的一致性,如果你需要,那么你必须自己实现。
猜你喜欢
  • 2011-04-15
  • 1970-01-01
  • 2012-08-20
  • 2019-09-22
  • 1970-01-01
  • 2014-12-12
  • 1970-01-01
  • 2018-01-31
  • 2021-04-27
相关资源
最近更新 更多