ConcurrentLinkedQueue上的迭代器不会迭代到下一个值

时间:2017-10-26 15:41:37

标签: java data-structures concurrency queue java.util.concurrent

我正在迭代它时更新ConcurrentLinkedQueue。从理论上讲,此队列上的迭代器不应该停止,直到达到队列结束。但是,在我的程序中(如下所示),迭代器在迭代队列的初始状态(没有更新)之后停止。我该怎么做才能克服这个问题?

public static void printTree(Node root) {
    Queue<Node>q=new ConcurrentLinkedQueue<Node>();
    q.add(root);

    Iterator<Node> iter = q.iterator();
    while(iter.hasNext()) {
        List<Node> childs = iter.next().getChildren();
        for(Node child:childs) {
            q.add(child);
        }
    }

    for (Node item:q) {
        System.out.println(item.getValue());
    }
}

它的输出是root的值(传递给函数的值)及其子值。它应该显示孩子的孩子的价值,但不是。似乎迭代器iter只迭代root,它首先被添加到队列而不是更多。

1 个答案:

答案 0 :(得分:1)

ConcurrentLinkedQueue#iterator()的javadoc中:

  

返回的迭代器(...)保证遍历元素   在构造迭代器时存在,并且可能(但不是   保证)反映施工后的任何修改。

基本上,当您创建迭代器时,它将在队列创建视图时提供视图。这是此Collection是线程安全的原因之一:更改队列将并行完成,即不影响现有迭代器。

在这种情况下无需使用线程安全集合。您可以使用支持ListIterator的List。 ListIterator是一个功能更强大的iterator,它支持添加元素:

List<Node>q=new LinkedList<Node>();
q.add(root);

ListIterator<Node> iter = q.iterator();
while(iter.hasNext()) {
    List<Node> childs = iter.next().getChildren();
    for(Node child:childs) {
        iter.add(child);
    }
}

for (Node item:q) {
    System.out.println(item.getValue());
}

这是该方法的替代实现,不使用迭代器,我更喜欢:

List<String> q = new LinkedList<>();
q.add(root);

while(!q.isEmpty()) {
  Node node = q.poll();
  q.addAll(node.getChildren());
  System.out.println(node.getValue());
}