加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

LinkedHashSet迭代时的java.util.ConcurrentModificationExcepti

发布时间:2020-12-15 04:12:01 所属栏目:Java 来源:网络整理
导读:请帮助我理解我得到的错误: private void replayHistory() { synchronized (alarmsHistory) { for (AlarmEvent alarmEvent : alarmsHistory) { LOG.error("replayHistory " + alarmEvent.type + " " + alarmEvent.source); sendNotification(alarmEvent.typ
请帮助我理解我得到的错误:

private void replayHistory() {
    synchronized (alarmsHistory) {
        for (AlarmEvent alarmEvent : alarmsHistory) {
            LOG.error("replayHistory " + alarmEvent.type + " " + alarmEvent.source);
            sendNotification(alarmEvent.type,alarmEvent.source,alarmEvent.description,alarmEvent.clearOnOtherStations,alarmEvent.forceClearOnOtherStations);         
        }
    }
}

以及向其添加元素的方法

private void addToAlarmsHistory(AlarmEvent alarmEvent) {
    synchronized (alarmsHistory) {
        LOG.error("addToAlarmsHistory " + alarmEvent.type + " " + alarmEvent.source);
        alarmsHistory.add(alarmEvent);
    }
}

两种方法和Set

private volatile Set< AlarmEvent> alarmsHistory = new LinkedHashSet< AlarmEvent>();

定义于

JmxGwReloadThread扩展了Thread类

这是一个内在的阶级

AlarmManager类

有方法

private void addToReplayHistory(AlarmEvent alarmEvent) {
    if ((jmxThread != null) && (jmxThread.isAlive())) {
        jmxThread.addToAlarmsHistory(alarmEvent);
    }
}

这是由不同的接口调用(无法确定何时和多久)

在某些时候,JmxThread启动并调用replayHistory方法

抛出java.util.ConcurrentModificationException,root来自

for (AlarmEvent alarmEvent : alarmsHistory) {

该代码可以尝试将一个元素添加到alarmsHistory和interator时

java.util.ConcurrentModificationException
    at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:390)
    at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:401)
    at AlarmManager$JmxGwReloadThread.replayHistory(AlarmManager.java:568)
    at AlarmManager$JmxGwReloadThread.run(AlarmManager.java:532)

在调用nextEntry时抛出异常,但不应该同步阻止这样的问题吗?

日志显示同步不起作用 – replayHistory应该遍历其所有元素(我可以确定它的多个单个HEARTBEAT_INFO FM),但它被addToReplayHistory调用中断.

2013-07-11 11:58:33,951 Thread-280 ERROR AlarmManager$JmxGwReloadThread.replayHistory(AlarmManager.java:570)  - replayHistory HEARTBEAT_INFO FM
2013-07-11 11:58:33,951 Thread-280 ERROR AlarmManager$JmxGwReloadThread.addToAlarmsHistory(AlarmManager.java:550)  -  addToAlarmsHistory HEARTBEAT_INFO FM
2013-07-11 11:58:33,952 Thread-280 ERROR Log4jConfigurator$UncaughtExceptionHandler.uncaughtException(Log4jConfigurator.java:253)  - Detected uncaught exception in thread: Thread-280

解决方法

OP(可能是大多数人)应该注意的一件事:

ConcurrentModificationException与多线程无关.

虽然多线程使其更容易发生,但这个问题的核心与多线程无关.

这主要是由场景造成的,

>从集合中获取迭代器,
>在完成使用该迭代器之前,该集合已在结构上进行了修改.
>继续使用迭代器2.迭代器将检测集合是否在结构上被修改并将抛出ConcurrentModificationException.

当然,并非所有集合都有这样的行为,例如ConcurrentHashMap的. “结构修改”的定义也因不同的集合而不同.

这意味着,即使我只有一个帖子,如果我做的话:

List<String> strings = new ArrayList<String>();
    //....
    for (String s: strings) {  // iterating through the collection
        strings.add("x");   // structurally modifying the collection
    }

我将得到ConcurrentModificationException,即使它发生在单线程中.

根据您的要求或问题,有不同的方法可以解决问题.例如

>如果仅仅是由于多线程访问,适当的同步访问可以是一种解决方案
>您可以使用Collection,迭代器可以安全地进行结构修改(例如ConcurrentHashMap)
>调整逻辑以便在修改集合时再次重新获取迭代器,或者使用迭代器进行修改(某些集合impls允许),或者确保在使用完迭代器后对集合进行修改.

鉴于您的代码似乎在alarmHistory上具有正确的同步,您需要检查两个方向

> sendNotification()中是否有任何可能的alarmHistory修改?例如,在alarmHistory中添加或删除?>是否有其他可能的不同步访问alarmHistory可能会修改结构?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读