Java流,从ConcurrentLinkedQueue

时间:2016-07-08 08:08:43

标签: java java-8 java-stream

我不确定如何做到这一点,我想迭代ConcurrentLinkedQueue(全部),删除第i个项目并在其上执行一些代码。

这就是我以前做的事情:

public static class Input {

    public static final ConcurrentLinkedQueue<TreeNode> treeNodes = new ConcurrentLinkedQueue<>();
}

public static class Current {

    public static final ConcurrentHashMap<Integer, TreeNode> treeNodes = new ConcurrentHashMap<>();
}

TreeNode是一个简单的类

    TreeNode treeNode = Input.treeNodes.poll();

    while (treeNode != null) {

        treeNode.init(gl3);

        Current.treeNodes.put(treeNode.getId(), treeNode);

        treeNode = Input.treeNodes.poll();
    }

这就是我尝试使用stream的方式:

    Input.treeNodes.stream()
            .forEach(treeNode -> {
                Input.treeNodes.remove(treeNode);
                treeNode.init(gl3);
                Current.treeNodes.put(treeNode.getId(), treeNode);
            });

我担心在forEach操作中删除项目可能容易出错。

所以我的问题是:

这样做是否安全和/或有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

正如您所假设的那样,在处理流时不应修改后备集合,因为您可能会得到ConcurrentModificationException(就像for(Object o:objectArray){}循环一样)

另一方面,不清楚你要删除哪个TreeNode,就像在当前情况下一样,似乎你希望删除List中的所有元素,对它们执行一些操作并将它们放在Map

您可以通过以下方式安全地获得当前的逻辑:

Input.treeNodes.stream()
         .map(treeNode -> {
             treeNode.init(gl3);
             Current.treeNodes.put(treeNode.getId(), treeNode);
         });
Input.treeNodes.clear();

答案 1 :(得分:2)

此行为由用于构建Spliterator的{​​{1}}确定。 ConcurrentLinkedQueue.spliterator()的文档说:

  

在此队列中的元素上返回Spliterator   返回的分裂器为weakly consistent

weakly consistent”暗示:

  

大多数并发Collection实现(包括大多数队列)也与通常的Stream约定不同,因为它们的迭代器和Spliterators提供弱一致性而不是快速失败遍历:

     
      
  • 他们可以与其他行动同时进行
  •   
  • 他们永远不会抛出java.util
  •   
  • 他们可以保证在施工时只存在一次元素,并且可能(但不保证)反映施工后的任何修改。
  •   

这意味着删除遇到的元素不会产生任何影响。

另一方面,当其他线程添加或删除元素时,关于这些元素的Stream操作的结果是不可预测的。

但是,您应该考虑ConcurrentModificationException不是队列的预期用例。