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)
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".
final. In any weird threading bug issue always
make everything you can final. I'm 99% sure one of those will fix it.
If all else fails, catch the ConcurrentModificationException and try cloning again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With