【发布时间】: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