我有一个调用更新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)
答案 0 :(得分:1)
我怀疑你是两次克隆botlist。一旦你创建了线程,
new updateVouchXML((BotLinkedMap<String, IPlayer>)botList.getPlayerData().clone())).start())
和另一次运行()。
中间副本this.players
字段不是最终。所以这可能是那些模糊的“过早发布”错误之一。 - 来自this.players的第二个克隆正在发生,而第一个克隆,到this.players,仍在“进行中”。
final
。总是在任何奇怪的线程错误问题
尽你所能final
。 我99%肯定其中一个会解决它。
如果所有其他方法都失败了,请捕获ConcurrentModificationException并再次尝试克隆。