并发修改异常的问题

时间:2013-01-03 04:40:29

标签: java multithreading exception concurrency

我有一个调用更新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));
        }

Bot链接地图

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

    }
}

WriteToXML

@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)

1 个答案:

答案 0 :(得分:1)

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

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

和另一次运行()。

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

  1. 尝试制作玩家final。总是在任何奇怪的线程错误问题 尽你所能final
  2. 只尝试克隆一次。
  3. 我99%肯定其中一个会解决它。

    如果所有其他方法都失败了,请捕获ConcurrentModificationException并再次尝试克隆。