如何在从LinkedList进行基于递归迭代器的删除时避免ConcurrentModificationException?

Gigaxel:

我一直在尝试通过将子级分配给其父级然后通过it.remove()以下方式将其删除来有效地创建树

for (OgOrganizationTreeDTO parent : parents) {
    setChildren(parent, organizationTree);
}

这是setChildren功能的实现

private void setChildren(OgOrganizationTreeDTO root, List<OgOrganizationTreeDTO> allOrganizations) {
    if (allOrganizations.isEmpty()) {
        return ;
    }
    Iterator<OgOrganizationTreeDTO> it = allOrganizations.iterator();
    while (it.hasNext()) {
        OgOrganizationTreeDTO potentialChild = it.next();
        if (potentialChild.getIdParentId() != null && potentialChild.getIdParentId().equals(root.getId())) {
            root.addChild(potentialChild);
            it.remove();
            setChildren(potentialChild, allOrganizations);
        }
    }
}

我正在使用LinkedList并得到一个ConcurrentModificationException我已经通过将的副本传递allOrganizations给递归setChildren函数解决了问题,例如new LinkedList<>(allOrganizations),但是副本部分需要O(n)时间,我不希望这样。

我也尝试使用LinkedBlockingQueue,但是发现删除需要O(n)时间。

我想利用LinkedList O(1)remove的优势,因此每当我添加一个孩子并在其上重复出现时,列表就会变小。

我还成功实现了一个解决方案,方法HashSet是将各个节点标记为可见,并将基本情况设置为hashSet.size() == allOrganizations.size(),但是我仍然在相同大小的List上重复执行此操作,因此这对我没有任何帮助。

有什么方法可以实现我使用LinkedList O(1)remove的目标,或者有更有效的替代方法呢?

维斯林·戴维多夫(Veselin Davidov):

我不知道如何使用递归,因为您实际上在每个递归调用中都创建了一个新的迭代器(allOrganizations.iterator()-创建新的迭代器实例)。因此,当您调用delete时,您需要为其他迭代器修改集合,这就是为什么它将引发该异常的原因。

  • 一种解决方案是使用一些CopyOnWriteList,它允许并发修改,但它只是传递列表的一个副本,而不是修改同一列表,因此将占用额外的内存。

  • 另一种解决方案是在OgOrganizationTreeDTO类中添加一些属性,以标记该行是否已被处理。在这种情况下,您无需将其从列表中删除,只需将其标记为已处理即可。

  • 但是无论如何,既然您在询问性能和大O,那么我可以为您提供另一个具有O(n)复杂度的解决方案。当然,需要在使用更多内存的情况下进行权衡,但这是标准内存与复杂性的问题...

    private static void setChildrenMap(OgOrganizationTreeDTO root, 
         List<OgOrganizationTreeDTO> allOrganizations) {
    
      Map<Integer, OgOrganizationTreeDTO> organizationsMap = new HashMap<>();
      organizationsMap.put(root.getId(), root);
    
      for (OgOrganizationTreeDTO element : allOrganizations) {
        organizationsMap.put(element.getId(), element);
      }
    
      for (OgOrganizationTreeDTO element : allOrganizations) {
         organizationsMap.get(element.getParentId()).addChild(element);
      }
    
    }
    

基本上,从哈希图中获取元素是恒定的时间,因此我们使用它来查找所需的父对象。如果期望元素包含错误的数据,则可能需要添加一些检查,因为organizationsMap.get(element.getParentId())可能会返回null

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在迭代时从“ ArrayList”中删除元素时避免“ ConcurrentModificationException”?

迭代器如何在添加时引发ConcurrentModificationException

迭代地图和更改值时如何避免ConcurrentModificationException?

迭代时如何仅在 ArrayList 中避免 ConcurrentModificationException?

如何在使用cypher与UNWIND进行迭代时删除关系

如何在std :: set上进行迭代时删除元素

如何避免在numpy中基于数组的函数内进行迭代?

如何在迭代期间添加项目时修复ConcurrentModificationException错误

如何删除LinkedList的元素在Java中嵌套迭代器

如何在不使用ConcurrentModificationException的情况下使用for-each循环进行迭代时修改Collection?

如何在从AutoPlugin进行编译时修改sourceGenerators?

在使用迭代器删除条目ConcurrentModificationException的

ConcurrentModificationException使用迭代器循环时

如何在迭代时从地图中删除?

如何在删除项目时迭代地图?

如何在迭代时从json删除项目?

遍历Collection,避免在循环中删除对象时避免ConcurrentModificationException

即使使用迭代器从arraylist中删除元素时,java.util.ConcurrentModificationException

如何在集合上进行迭代时删除集合中的相邻条目

如何在我的自定义LinkedList实现中避免不必要的递归?

如何在从表单发布结果的对象中进行迭代并仅获取具有值的元素?

在遍历和删除ArrayList中的元素时如何避免java.util.ConcurrentModificationException

如何在并发线程中处理`values()`和`put()`时如何避免HashMap“ ConcurrentModificationException”?

使用自写的LinkedList迭代器进行无限迭代

如何在JPA和Hibernate中合并实体时避免java.util.ConcurrentModificationException

快速失败的迭代器如何知道抛出“ ConcurrentModificationException”时修改了基础结构?

如何在HashMap上使用双重迭代器修复'java.util.ConcurrentModificationException'

ConcurrentModificationException的使用列表迭代器的Java删除元素

ConcurrentModificationException的使用迭代器