我不确定如何做到这一点,我想迭代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
操作中删除项目可能容易出错。
所以我的问题是:
这样做是否安全和/或有更好的方法吗?
答案 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
不是队列的预期用例。