java8 concurrentmodificationexception在执行任何类型的迭代时

fae0ux8s  于 2021-07-09  发布在  Java
关注(0)|答案(1)|浏览(477)

我花了两个星期试图解决这个问题,但没有成功十
它发生在我进行任何类型的迭代时,但主要是在使用#foreach时。
我没有以任何方式修改列表,也没有修改它的元素,所以这对我来说非常尴尬。示例代码:

Map<Season, List<Team>> map = fetcher.getTeamsIn(ids);

    Set<Team> toCreateTeams = new HashSet<>();
    Set<Team> toUpdateTeams = new HashSet<>();

    map.forEach((k, v) -> {
        toCreateTeams.addAll(v.stream().filter(t -> !persistedTeams.containsKey(t.getId())).collect(Collectors.toSet()));
        toUpdateTeams.addAll(v.stream().filter(t -> {
            Date latestPersistedUpdate = persistedTeams.get(t.getId());
            return latestPersistedUpdate != null && t.getLastUpdated().after(latestPersistedUpdate);
        }).collect(Collectors.toSet()));
    });

Map在#getteamsin中示例化 new HashMap<>(); 尝试在eclipse中打开异常以查看某个线程是否在做一些疯狂的事情,但在我看来一切都很正常。在下面的pics中,在迭代 map .


我也开始有一些非常奇怪的行为,比如永远陷入一个lambda表达式。在本例中,在我看来eclipse正在表达式中停止(出于某种未知的原因),就好像在行中设置了某个断点一样。当我暂停执行并只恢复有问题的线程时,流就会恢复正常(直到下一个lambda表达式)或一些疯狂的concurrentmodificationexception。

整个过程在我看来就像是一个疯狂的eclipse bug,但如果是这样的话,我真的不想重建我的环境。
我在用

Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

在linux mint上。
谢谢!

--更新1--

要清楚的是:即使在这个简单的例子中,错误也在发生:

map.forEach((k, v) -> {
    System.out.println("Test" + k.getId());
});

一些可能很重要的随机信息:只有在打印完Map的最后一个元素之后,异常才会爆炸!

--更新2--

关于update1中的随机信息,这真的不重要,因为出于性能原因(至少在hashmap和arraylist中), ConcurrentModificationException 只有在迭代结束时,通过比较元素数组的实际大小和预期大小来检查。
方法#getteamsin的代码:

public Map<Season, List<Team>> getTeamsIn(List<Season> seasons) throws InterruptedException {
    final CountDownLatch latch = new CountDownLatch(seasons.size());
    Map<Season, List<Team>> teamsInSeason = new HashMap<>();
    for (Season s : seasons) {
        httpclient.execute(new HttpGet(String.format(URL, s.getId())),
                new Callback(latch) {

                    @Override
                    public void completed(final HttpResponse response) {
                        super.completed(response);
                        try {
                            teamsInSeason.put(s, new TeamsUnmarshaller().unmarshal(response.getEntity().getContent()));
                        }
                        catch (IllegalStateException | IOException e) {
                            // TODO Auto-generated catch block
                            System.out.println(e);
                        }
                    }

                });
    }
    latch.await();
    return teamsInSeason;
}
``` `Callback` 班级公正 `implements FutureCallback<HttpResponse>` 以及 `countDown()` 这个 `latch` 在所有回调方法中(#取消、#完成和#失败)。
dtcbnfnu

dtcbnfnu1#

好的,刚刚发现问题。我在方法#getteamsin中重写的#completed方法花费的时间太长(感谢jaxb)。自从 countDown() (被召入) super.completed(response) )是在 teamsInSeason.put(s, new TeamsUnmarshaller().unmarshal(response.getEntity().getContent())); ,我们有个问题。
解决方法简单而难看:

@Override
public void completed(final HttpResponse response) {
    try {
        teamsInSeason.put(s, new TeamsUnmarshaller().unmarshal(response.getEntity().getContent()));
    }
    catch (IllegalStateException | IOException e) {
        // TODO Auto-generated catch block
        System.out.println(e);
    } finally {
        super.completed(response);
    }
}

奇怪的eclipse行为(由于某种未知的原因被困在某个假想的断点中),如果它持续存在,我认为是另一个主题的问题。
谢谢大家的帮助和时间!

相关问题