3

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

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

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

/**
*
* @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));
        }

机器人链接地图

/*
* 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)
4

1 回答 1

1

我怀疑您正在克隆僵尸列表两次。一旦你创建线程,

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

还有一次在 run() 中。

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

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

我有 99% 的把握其中一个会修复它。

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

于 2013-01-03T05:49:10.953 回答