【问题标题】:Skip synchronization when iterating over a LinkedHashSet and no remove is done?迭代 LinkedHashSet 时跳过同步并且不删除?
【发布时间】:2016-09-05 16:04:21
【问题描述】:

我必须在多个线程之间共享的 Set 上进行迭代。像这样的代码:

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");
}

我已经阅读了 synchronizedSet 的 javadoc,它指出:

用户必须手动同步返回的 迭代时设置:

Set s = Collections.synchronizedSet(new HashSet());
  ...   synchronized (s) {
  Iterator i = s.iterator(); // Must be in the synchronized block
  while (i.hasNext())
      foo(i.next());  
  }   

不遵循此建议可能会导致不确定的行为。

但是,我还在this answer 上读到,LinkedHashSet 提供了插入顺序迭代。我的 Set 的所有线程都是

  • 正在尝试添加一个新对象
  • 如果添加操作返回false,则对其进行迭代以测试对象
  • 永远不要执行清除或移除,集合只会增长。

有了所有这些假设,我的猜测是我不需要对 Set 执行同步,因为即使另一个线程在我迭代它时添加了一个新对象,它也会在集合的末尾并且我将在到达插入点之前找到我正在寻找的对象。

这对吗?

【问题讨论】:

  • "我猜我不需要在 Set 上执行同步,因为......" 我会阻止你。你做。如果您正在对集合进行修改(例如添加元素),您总是需要同步。
  • 这里是good example,说明为什么你不应该做出这样的假设。这个故事的寓意是,您不能仅通过通过其公共 API 观察到的内容来推断实现的内部工作原理。如果您想要一个无锁集合,请使用无锁集合,而不是应该同步但不同步的集合。
  • 没想过用无锁合集,谢谢提示
  • 我正在考虑使用 ConcurrentSkipListSet。看起来很有希望

标签: java multithreading synchronization set synchronized


【解决方案1】:

不,您必须同步,如Javadoc中所述:

请注意,此实现不同步。如果多个线程同时访问链接的哈希集,并且至少有一个线程修改了该集,则它必须在外部同步。

如果您有一个线程在另一个线程向其添加元素时迭代该集合,您将获得ConcurrentModificationException

这个类的迭代器方法返回的迭代器是快速失败的:如果集合在迭代器创建后的任何时候被修改,除了通过迭代器自己的remove方法之外,迭代器将抛出一个@987654324 @。

【讨论】:

  • 我希望他们没有强制执行这种快速失败的行为。当除了新对象之外什么都不会发生时,迭代数组有什么问题?
  • @Aldian 这不是一个值得处理的常见案例。
  • @Aldian:谁能说“什么都不会发生”?您围绕 LinkedHashSet 创建了一个同步包装器,其 Iterator 甚至不知道它已被包装,因此继续保护自己免受不一致状态的影响。作为旁注,该迭代器的当前实现实际上是LinkedHashMap$LinkedHashIterator 的子类型,它必须处理LinkedHashMap 对访问重新排序的支持,甚至与不支持插入的普通HashMap 共享代码顺序遍历,因此,将在插入时使迭代器无效。
猜你喜欢
  • 2017-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-31
  • 2021-07-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多