Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with concurrent modification exception

I have a thread im calling that updates an XML file.

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

In this threads run method I get a Concurrent Modification error when im cloning the map. Ive dealt with Concurrent modification issues before, and the usual solution is close the object your iterating over. Ive never had an issue where the cloning of the object caused the exception. Any Advice?

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

Errors specifically here

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 Linked 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);

    }
}

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;

}

Stack Trace

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)
like image 746
meriley Avatar asked Mar 18 '26 04:03

meriley


1 Answers

I am suspicious that you are cloning botlist twice. Once when you create the thread,

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

and another time in run().

And the intermediate copy, the this.players field, is not final. So this may be one of those obscure "premature publishing" bugs. - The 2nd clone from this.players is happening while the 1st clone, to this.players, is still "in progress".

  1. Try making players final. In any weird threading bug issue always make everything you can final.
  2. Try cloning only once.

I'm 99% sure one of those will fix it.

If all else fails, catch the ConcurrentModificationException and try cloning again.

like image 116
user949300 Avatar answered Mar 19 '26 18:03

user949300



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!