java - 并发修改异常问题

标签 java multithreading exception concurrency

我有一个更新 XML 文件的即时调用线程。

    public synchronized void updateVouchXML() {
        new Thread(new updateVouchXML((BotLinkedMap<String, IPlayer>)botList.getPlayerData().clone())).start();
    }

在这个线程运行方法中,我在克隆 map 时遇到并发修改错误。我之前处理过并发修改问题,通常的解决方案是关闭您迭代的对象。我从来没有遇到过对象的克隆导致异常的问题。有什么建议吗?

/**
*
* @author Mark
*/
public class updateVouchXML implements Runnable {

    BotLinkedMap<String, IPlayer> players;
    DocumentBuilderFactory dbf;
    DocumentBuilder db;
    Document doc;
    Element vdata;

    public updateVouchXML(BotLinkedMap<String, IPlayer> players) {

        this.players = players;
        dbf = DocumentBuilderFactory.newInstance();
        try {
            db = dbf.newDocumentBuilder();
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(updateVouchXML.class.getName()).log(Level.SEVERE, null, ex);
        }
        doc = db.newDocument();
    }

    @Override
    public void run() {
        try {


            vdata = doc.createElement("vouchdata");
            doc.appendChild(vdata);


            BotLinkedMap<String, IPlayer> clone = (BotLinkedMap<String, IPlayer>) players.clone();
            for (Entry<String, IPlayer> e : clone.entrySet()) {
                IPlayer p = e.getValue();
                vdata.appendChild(p.writeToXML(doc));
            }




            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer(); // An identity transformer
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
            DOMSource source = new DOMSource(doc);
            StreamResult result = new StreamResult(new File("vouchdata.xml"));

            transformer.transform(source, result);
        } catch (TransformerException ex) {
            Logger.getLogger(updateVouchXML.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

具体错误在这里

BotLinkedMap<String, IPlayer> clone = (BotLinkedMap<String, IPlayer>) players.clone();
        for (Entry<String, IPlayer> e : clone.entrySet()) {
            IPlayer p = e.getValue();
            vdata.appendChild(p.writeToXML(doc));
        }

机器人链接 map

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package InHouseLeague.Connections;

import java.util.LinkedHashMap;

/**
*
* @author Mark
*/
public class BotLinkedMap<O1, O2> extends LinkedHashMap<O1, O2> {

    @Override
    public O2 get(Object key) {
        if (key instanceof String) {
            return super.get(((String) key).toLowerCase());
        }

        return super.get(key);
    }

    @Override
    public boolean containsKey(Object key) {
        if (key instanceof String) {
            return super.containsKey(((String) key).toLowerCase());
        }

        return super.containsKey(key);
    }

    @Override
    public O2 remove(Object key) {
        if (key instanceof String) {
            return super.remove(((String) key).toLowerCase());
        }

        return super.remove(key);
    }


    @Override
    public O2 put(O1 key, O2 value) {

        O1 modKey = key;
        O2 modVal = value;

        if (key instanceof String) {
            modKey = (O1) ((String) key).toLowerCase();
        }

        if (value instanceof String) {
            modVal = (O2) ((String) value).toLowerCase();
        }
        return super.put(modKey, modVal);

    }
}

写入XML

@Override
public Element writeToXML(Document doc) {
    Element udata = doc.createElement("player");
    try {


        udata.setAttribute("ban", new Long(ban.getDurationMilliseconds()).toString());

        Attr name = doc.createAttribute("name");
        name.setValue(getUserNamePlain());
        udata.setAttributeNode(name);

        Attr qauth = doc.createAttribute("qauth");
        qauth.setValue(getQAUTH().toLowerCase());
        udata.setAttributeNode(qauth);

        Attr rankz = doc.createAttribute("rank");
        rankz.setValue(getRankString().toLowerCase());
        udata.setAttributeNode(rankz);

        Attr vouchedByz = doc.createAttribute("vouchedBy");
        vouchedByz.setValue(getVouchedBy().toLowerCase());
        udata.setAttributeNode(vouchedByz);

        Element eloz = doc.createElement("elo");
        eloz.appendChild(doc.createTextNode(getELO().toString()));
        udata.appendChild(eloz);

        Element matchez = doc.createElement("matches");
        matchez.appendChild(doc.createTextNode(getMatches().toString()));
        udata.appendChild(matchez);

        Element winz = doc.createElement("wins");
        winz.appendChild(doc.createTextNode(getWins().toString()));
        udata.appendChild(winz);

        Element mvpNode = doc.createElement("mvp");
        for (MVP m : getMVP()) {
            mvpNode.appendChild(m.writeToXML(doc));
        }
        udata.appendChild(mvpNode);

        Element truantNode = doc.createElement("truant");
        truantNode.setAttribute("level", new Integer(getTruantCount()).toString());
        for (Truant m : getTruantList()) {
            truantNode.appendChild(m.writeToXML(doc));
        }
        udata.appendChild(truantNode);

        Element history = doc.createElement("history");
        for (GameSummary game : getGameHistory()) {
            history.appendChild(game.writeToXML(doc));
        }

        udata.appendChild(history);
    } catch (Exception ex) {
         udata = doc.createElement("player"); 
    }

    return udata;

}

堆栈跟踪

Exception in thread "Thread-13" java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:390)
at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:409)
at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:408)
at java.util.HashMap.putAllForCreate(HashMap.java:451)
at java.util.HashMap.clone(HashMap.java:682)
at InHouseLeague.Workers.updateVouchXML.run(updateVouchXML.java:55)
at java.lang.Thread.run(Thread.java:722)

最佳答案

我怀疑你在克隆 botlist 两次。一旦创建线程,

new updateVouchXML((BotLinkedMap<String, IPlayer>)botList.getPlayerData().clone())).start())

还有一次在 run() 中。

中间副本,this.players 字段,不是最终的。所以这可能是那些晦涩的“过早发布”错误之一。 - this.players 的第二次克隆正在发生,而 this.players 的第一个克隆仍在“进行中”。

  1. 尝试让玩家最终。在任何奇怪的线程错误问题中总是 尽你所能 final
  2. 只尝试克隆一次。

我 99% 确定其中一个会解决它。

如果一切都失败了,捕获 ConcurrentModificationException 并再次尝试克隆。

关于java - 并发修改异常问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14133145/

相关文章:

java - Gradle Eclipse JSF项目java.lang.ClassNotFoundException javax.faces.webapp.FacesServlet

java - 没有找到接口(interface) java.util.List Rest API Spring boot 的主构造函数或默认构造函数

multithreading - 多线程模型之间的差异

javascript - 为什么我的 JScript(Windows 脚本宿主)在未捕获的异常中以 0 退出?

c++ - Bad Re-throw 编译但在运行时崩溃

尝试使用 MongoDB BulkWriteOperation 时出现 java.lang.IllegalStateException

java - 根据用户输入生成字母金字塔

java - 使用 .equals() 比较两个字符串返回 False,但它们的字节数组相等

c - 在多个任务访问的函数中保留非静态变量值

c++ - 使用pthread在c++中运行后台进程