Java 在LinkedHashSet上迭代且未执行删除时跳过同步?
我必须迭代多个线程共享的集合。类似于以下代码:Java 在LinkedHashSet上迭代且未执行删除时跳过同步?,java,multithreading,synchronization,set,synchronized,Java,Multithreading,Synchronization,Set,Synchronized,我必须迭代多个线程共享的集合。类似于以下代码: class MyObj{} final static Set<MyObj> instances = Collections.synchronizedSet(new LinkedHashSet<MyObj>()); // returns the same object from the set if any, or add it if not found public MyObj test2(MyObj a){ if
class MyObj{}
final static Set<MyObj> instances = Collections.synchronizedSet(new LinkedHashSet<MyObj>());
// returns the same object from the set if any, or add it if not found
public MyObj test2(MyObj a){
if(instances.add(a))
return a;
for(MyObj o : instances){
if(o.equals(a))
return o;
}
throw new IllegalStateException("Impossible to reach this line");
}
不遵循此建议可能会导致不确定性行为
但是,我也了解到LinkedHashSet提供了插入顺序迭代。我这套衣服穿一根线就够了
- 正在尝试添加一个新对象
- 如果add操作返回false,则对其进行迭代以测试对象
- 切勿执行清除或删除,集合只能增长
根据所有这些假设,我的猜测是,我不需要在集合上执行同步,因为即使另一个线程在我对其进行迭代时添加了一个新对象,它也将位于集合的末尾,并且我将在到达插入点之前找到我要查找的对象 是否正确?否,您必须同步,如中所述: 请注意,此实现未同步。如果多个线程同时访问链接的哈希集,并且至少有一个线程修改该集,则必须在外部对其进行同步 如果一个线程在另一个线程向其添加元素时对集合进行迭代,则会得到一个
ConcurrentModificationException
该类的迭代器方法返回的迭代器是快速失效的:如果在创建迭代器后的任何时间以任何方式修改集合,除了通过迭代器自己的remove
方法之外,迭代器将抛出ConcurrentModificationException
否,必须同步,如中所述:
请注意,此实现未同步。如果多个线程同时访问链接的哈希集,并且至少有一个线程修改该集,则必须在外部对其进行同步
如果一个线程在另一个线程向其添加元素时对集合进行迭代,则会得到一个ConcurrentModificationException
该类的迭代器方法返回的迭代器是快速失效的:如果在创建迭代器后的任何时间以任何方式修改集合,除了通过迭代器自己的remove
方法之外,迭代器将抛出ConcurrentModificationException
“我猜我不需要在片场上执行同步,因为…”我会在那里阻止你。是的。如果要对集合进行修改(例如添加元素),则始终需要同步。以下是不应进行此类假设的原因。这个故事的寓意是,你不能仅仅通过你可以通过它的公共API观察到的东西来推理实现的内部工作。如果您想要无锁集合,请使用无锁集合,而不是应该同步但不同步的集合。我没有考虑使用无锁集合,谢谢您让我考虑使用ConcurrentSkipListSet。看起来很有希望“我猜我不需要在片场执行同步,因为……”我会在这里阻止你。是的。如果要对集合进行修改(例如添加元素),则始终需要同步。以下是不应进行此类假设的原因。这个故事的寓意是,你不能仅仅通过你可以通过它的公共API观察到的东西来推理实现的内部工作。如果您想要无锁集合,请使用无锁集合,而不是应该同步但不同步的集合。我没有考虑使用无锁集合,谢谢您让我考虑使用ConcurrentSkipListSet。看起来很有希望我希望他们不要强制执行这种快速失败的行为。当最后除了新对象之外什么都不可能发生时,对数组进行迭代有什么错?@Aldian这种情况不太常见,不值得处理。@Aldian:谁会说“什么都不可能发生”?您在
LinkedHashSet
周围创建了一个同步包装器,其Iterator
甚至不知道它已被包装,从而继续保护自己免受不一致状态的影响。作为旁注,该迭代器的当前实现实际上是LinkedHashMap$LinkedHashIterator
的一个子类型,它必须处理LinkedHashMap
对访问时重新排序的支持,甚至与不支持插入顺序遍历的普通HashMap
共享代码,因此,将在插入时使迭代器无效。我希望他们没有强制执行这种快速失败行为。当最后除了新对象之外什么都不可能发生时,对数组进行迭代有什么错?@Aldian这种情况不太常见,不值得处理。@Aldian:谁会说“什么都不可能发生”?您在LinkedHashSet
周围创建了一个同步包装器,其Iterator
甚至不知道它已被包装,从而继续保护自己免受不一致状态的影响。作为旁注,该迭代器的当前实现实际上是LinkedHashMap$LinkedHashIterator
的一个子类型,它必须处理LinkedHashMap
对访问时重新排序的支持,甚至与不支持插入顺序遍历的普通HashMap
共享代码,因此,将在插入时使迭代器无效。
Set s = Collections.synchronizedSet(new HashSet());
... synchronized (s) {
Iterator i = s.iterator(); // Must be in the synchronized block
while (i.hasNext())
foo(i.next());
}