【发布时间】:2013-05-24 20:01:09
【问题描述】:
class Nodes 有getNodes() 方法,即not synchronized。但是List<Node> nodes - is synchronized。许多线程可以连接到它,在其中更改nodes。
像这样:
class Nodes {
List<Node> nodes = Collections.synchronizedList(new ArrayList<Node>() );
public List<Nodes> getNodes() { return nodes; }
...
}
客户端代码:
Nodes nodes;
synchronized(nodes) {
for(Node node: nodes.getNodes()) {
...
}
}
对此我没有审讯测试,但是:
我应该使用while(iterator.hasNext()) { var = iterator.next() }而不是for循环吗?
因为我知道当我尝试在 for 循环中删除 nodes.remove(node) 时,它会以 ConcurentModificationException 失败。
编辑:(相关问题)
如果迭代器是好东西,那么有这个代码(客户端代码):
Iterator<Node> iter = nodes.getNodes().iterator();
while (iter.hasNext()) { // line 1
Node node = iter.next(); // line 2
}
反正也不安全:
1. thread1 goes to line 1, hoping that now iter would return him next() value.
2. but at that moment thread2 delete that value.
3. thread1 has Exception and fails.
这是否意味着无论如何我都应该在客户端进行锁定。这是我不想做的。
我有一个解决方案:
while (iter.hasNext()) {
try {
Node node = iter.next();
...
} catch (NoSuchElementException ex) {continue;} // handle exception - do more try
}
编辑:
我的答案是:使用 CopyOnWriteArrayList。我什至可以和 for-loop 在一起。
但是另一种选择:只需向客户返回列表的副本,让他们知道他们想要什么。因为在列表中同时提供“快照迭代器”和真实数据有点奇怪(不一致)。
【问题讨论】:
-
总是推荐在多线程环境下使用Iterator..
-
@Ankur 你能澄清你的评论吗?增强的 for 确实在幕后使用了迭代器。
-
另请注意,
ConcurrentModificationException与多线程无关。 -
“总是建议在多线程环境下使用Iterator”这条评论的依据是什么?
标签: java concurrency