ConcurrentHashMap的KeySet迭代器是否线程安全?

3
我正在尝试探索“ThreadSafe是什么意思?”
以下是我的理解:
对我来说,ThreadSafe似乎是允许多个线程同时访问集合,而不考虑其同步。例如,在没有synchronized关键字的任何方法上,都是线程安全的,这意味着多个线程可以访问它。
开发人员可以选择在此方法上维护一些逻辑(同步),以在多个线程访问时维护数据完整性。这与线程安全无关。
如果我上面的陈述是错误的,请阅读下面的JAVA DOC for `ConcurrentHashMap:`
keySet:该视图的迭代器是“弱一致”的迭代器,永远不会引发ConcurrentModificationException,并保证遍历元素时按照迭代器构造时存在的方式进行,并且可能(但不保证)反映构造后的任何修改。
上面的声明表示,当多个线程修改集合时,keySet迭代器将无法保证数据完整性。
请问,* ConcurrentHashMap的KeySet迭代器是否线程安全?
我的线程安全理解正确吗?

5
你的问题本身就已经有了答案。 - codingenious
1
就Javadoc而言,这非常清晰,没有任何答案可以更好地或更清晰地解释它。您到底不理解什么? - Bohemian
ConcurrentHashMap的keySet()方法是线程安全的,因此可能无需同步或复制。 - Prashant Shilimkar
1
“迭代器永远不会抛出ConcurrentModificationException,并保证遍历元素时与迭代器构造时相同” - 这足以使某些东西成为“线程安全”。问题是,您如何定义“线程安全”... - Tadas S
@afk5min是您对线程安全的定义吗?这意味着线程安全不能保证对集合所做的修改,只是允许多个线程遍历元素吗? - Kanagavelu Sugumar
“线程安全”意味着在同时访问同一对象时不会出现未定义行为(或者当可以确定通过继续执行将绝对发生未定义行为时,没有未检查的异常)。 - Tadas S
3个回答

3

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

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


那么你的意思是在访问时,线程安全已经失去了数据完整性/一致性..? - Kanagavelu Sugumar

3
java.util.concurrent包的基本思想是提供一组数据结构,可以在没有强一致性的情况下提供线程安全的访问。这样,这些对象比正确锁定的对象实现更高的并发性。
线程安全意味着即使没有任何显式同步,也不会破坏对象。在HashTableHashMap中,一些方法可能存在多线程访问的问题,例如remove方法,该方法首先检查元素是否存在,然后删除它。这些方法在ConcurrentHashMap中被实现为原子操作,因此您不需要担心会丢失某些数据。
但这并不意味着该类自动为每个操作加锁。高级操作,如putAll和迭代器,未进行同步。该类不提供强一致性。您的操作的顺序和时间保证不会破坏对象,但不能保证生成准确的结果。
例如,如果您同时使用putAll调用打印对象,则可能会看到部分填充的输出。同时使用新插入的迭代器也可能无法反映所有插入,正如您引用的那样。
这与线程安全不同。即使结果可能令您惊讶,您可以确信没有任何东西丢失或意外覆盖,元素被添加到和从对象中删除而没有任何问题。如果此行为对您的要求足够,请使用java.util.concurrent类。如果需要更多的一致性,则需要使用java.util中的同步类或自己进行同步。

很好的答案。大多数情况下,绝对不需要进行“序列化”(通过synchronized等将并发调用转换为任意顺序的顺序调用)或“确定性序列化”,其中并发调用被转换为特定、可重现的顺序的顺序调用。这基本上就是为什么“线程安全”有完全不同的含义。 - Tadas S

1
根据您的定义,ConcurrentHashMap.keySet()返回的Set是线程安全的。但是,正如您所引用的内容所指出的那样,它可能会以非常奇怪的方式运作。
  1. 作为一个Set,条目可能会随机出现或消失。即如果您在同一对象上两次调用contains,则两个结果可能不同。
  2. 作为一个Iterable,您可以在两个不同的线程中开始其基础对象的两个迭代,并发现这两个迭代枚举了不同的条目。
  3. 此外,contains和迭代也可能不匹配。
然而,如果您在拥有Set时锁定底层的Map以防止修改,则不会发生此活动,但这并不意味着该结构不是线程安全的。

所以我看到使用迭代器存在很多不一致性;那么为什么它被称为线程安全呢...?或者说,线程安全和数据一致性无关吗...? - Kanagavelu Sugumar
@KanagaveluSugumar - 线程安全意味着通过多个线程访问它不会导致程序崩溃或出错。但是,如果你关心的话,它可能会给出一些不一致的结果 - 这是你自己需要防范的。开发人员可以选择在这个方法上维护一些逻辑(同步)来保持数据完整性,以便在多线程访问时进行维护。 - OldCurmudgeon
哦。。。?是吗。。?那么我的理解是正确的吗..?这个https://dev59.com/GG015IYBdhLWcg3w6QA0问题的最佳答案是错误的,是吗..? - Kanagavelu Sugumar
在我看来,“线程安全”意味着,如果您在写入时没有使用synchronized,则该结构可能会受到破坏。这并不要求线程之间的一致性,如果您需要,则必须自行实现。- @KanagaveluSugumar - OldCurmudgeon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接