【问题标题】:ConcurrentModificationException in my own code我自己的代码中的 ConcurrentModificationException
【发布时间】:2016-11-04 16:14:59
【问题描述】:

我认为我的解决方案被错误地误认为是另一个问题的解决方案。它也已被编辑,因此看起来解决方案是重复项所指向的解决方案,但这显然没有解决我的问题,只是避免了引发的异常(问题的表面)。由于我重新打开问题的努力无济于事,因此我重新打开了一个here


我收到了ConcurrentModificationException,但我无法解决这个问题。所以我从列表中删除了一系列元素,我得到了一个错误。

这是错误:

04-Nov-2016 15:49:50.488 SEVERE [http-nio-8080-exec-199] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [Faces Servlet] in context with path [/...] threw exception [java.util.ConcurrentModificationException] with root cause
 java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:886)
    at java.util.ArrayList$Itr.next(ArrayList.java:836)
    at com.ex.PersonController.removeGroup(...)
    at ....

Java 代码:

public void removeGroup(int age) {
    if (person != null) {
        List<Person> friends = person.getFriends();
        List<Person> removeFriends = new ArrayList<>();
        if (friends != null) {
            for (Person p : friends) {
                if (p.getAge() == age) {
                    removeFriends.add(p);
                } 
            }
            friends.removeAll(removeFriends);
        }
    }

编辑: 请注意,this 显然没有解决我的问题。虽然它避免了引发错误,但是 JSF 显示的结果不正确。是否有可能 JSF 在我的列表未完全更新时尝试刷新?


EDIT2: 我不认为这是重复的。我在一些测试中遇到的错误在thisthis 中消失了(请注意,即使使用 .add() 方法,由于某种原因我也遇到了同样的错误)。但是 JSF 仍然没有打印出我所期望的。我再次编写了 BalusC 从我的问题中删除的代码,并提供了更多信息:

xhtml Java 代码:

<c:forEach items="#{personController.groupedPersons}" var="personG">
    <h:commandButton action="#{personController.removeGroup(personG.key)}" type="submit" value="Remove" >
        <f:ajax render="@form" />
    </h:commandButton>
    #{personG.key} - #{personG.value.size()}
</c:forEach>

所以我第一次执行页面时,personController.groupedPersons 返回正确的人员列表(HashMap&lt;Integer, List&lt;Person&gt;&gt;)并打印出来就好了。在这一点上,我有 2 组:一组 3 个相同年龄的人和另一个不同年龄的人。当我点击 remove 3 个同龄人的组时,我会跟踪代码并使用迭代器删除所有必要的人,而不会引发ConcurrentModificationExceptionperson.getFriends(); 的返回列表 size = 1,这是正确的。然后 ajax 代码呈现表单。再次调用personController.groupedPersons 并按预期返回 1 个人。我已经验证了,这是我真正期望的回归人。但是 JSF 确实打印了错误的 #{personG.key}(我删除的那个)和 null #{personG.value.size()}

我知道这可能很难理解,但你能想到任何解释吗?


编辑 3: 这更有趣......如果我删除有 1 人的组,它会被删除,然后 JSF 会正确打印有 3 人的组。如果我删除包含 3 个人的组,他们将被删除并且 JSF 打印(正如我在 EDIT2 中所说)我刚刚删除的组的 key 并且 size() 为空。在我修改列表的同时,JSF 刷新页面之间是否存在并发问题? (这最初是我担心的,ConcurrentModificationException 来自 XHTML 和我的托管 bean 之间的并发问题,而不仅仅是托管 Bean 的代码中)。这可以解释为什么我得到了ConcurrentModificationException,即使我在列表中添加而不是从列表中删除。

【问题讨论】:

  • 你真的不应该编辑你的问题并彻底改变它。它使所有答案无效,并为后代破坏了问题。
  • 我没有完全编辑问题。正如你在历史中看到的那样,它是 BalusC。我很欣赏编辑,但我仍然认为也许 JSF 有事可做(也许没有,这就是他完全删除所有内容的原因)
  • 并发修改异常与JSF无关。 JSF 没有打印您所期望的事实是一个不同的问题(就像您发布的stackoverflow.com/questions/40442340/…),这也是一个“重复”。 JSF 的行为与您使用它的方式完全一致。
  • 我认为您的评论现在已经很清楚了,谢谢。我知道 ConcurrentModification 与直接无关,但我认为 JSF 和我的代码之间可能间接存在并发问题(即使我无法在任何测试中成功验证这一点)。由于 JSF 实际上打印了一些东西,这让我很困惑。

标签: java jsf-2 concurrentmodification


【解决方案1】:

在 Java 中,不允许遍历列表 (friends) 并在循环中从中删除元素 (friends.remove(p))。这会抛出一个ConcurrentModificationException

您可以改用Iterator

Iterator<Person> iterator = friends.iterator();
while (iterator.hasNext()) {
    if (iterator.next().getAge() == age) {
        iterator.remove();
    }
}

编辑:

您使用removeFriends.add(p); 的方法应该有效。你不会得到一个并发修改异常。但是,如果您的基础列表不支持removeAll,您最终可能会得到UnsupportedOperationException。例如Arrays.asList(...) 就是这种情况。如果你包装你的friends 列表是new ArrayList(friends); 你应该很高兴:

public void removeGroup(int age) {
  if (person != null) {
    List<Person> friends = new ArrayList<>(person.getFriends());
    List<Person> removeFriends = new ArrayList<>();
    if (friends != null) {
        for (Person p : friends) {
            if (p.getAge() == age) {
                removeFriends.add(p);
            } 
        }
        friends.removeAll(removeFriends);
    }
}

之后别忘了设置好友列表:

person.setFriends(friends);

【讨论】:

  • 这是我做的测试之一,你就在里面。但是我对removeFriends.add(p); 使用的方法呢?对我来说似乎没问题
  • 您的建议避免了异常。但我没有得到正确的结果......似乎代码出于某种原因在中间停止了循环。或者列表没有正确显示在 xhtml 代码中...
  • 您使用removeFriends.add(p); 的方法也应该有效。你不会得到一个并发修改异常。但是,如果您的基础列表不支持removeAll,您最终可能会得到UnsupportedOperationException。例如Arrays.asList(...) 就是这种情况。如果你包装你的friends 列表是new ArrayList(friends); 你应该很高兴。
  • 我知道,但它不起作用......错误的代码是(正如我在原始未编辑问题中所说)第二种方法,但我得到了 .add() 的并发错误版本。我想 JSF 和我的代码之间还有别的东西吗?
猜你喜欢
  • 2011-03-02
  • 1970-01-01
  • 2021-08-19
  • 2020-01-09
  • 1970-01-01
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
  • 2014-08-01
相关资源
最近更新 更多