我目前正在开发一个软件工程类型类的项目,并遇到我认为奇怪的错误。根据我已经完成的研究/调试,当 next()方法修改HashMap时,通常会抛出Java ConcurrentModificationException 被称为。
为了让你了解问题领域,这是一个国际象棋游戏,我决定将死。目前我的代码结构如下:
这段代码在循环时生成 ConcurrentModificationException ,尽管HashMap处于与迭代开始时相同的状态 - 大小和精确值。
任何可能导致这种情况的想法?
循环:
for(ValidatorCoordinate key: keys){
if(board.findPiece(key).getPieceType() != XiangqiPieceType.GENERAL
&& moveValid(key, spaceBetween, color)
&& tryBlock(key, spaceBetween, dst, color)){
return true;
}
}
tryBlock()(修改HashMap的方法)
private boolean tryBlock(ValidatorCoordinate source,
ValidatorCoordinate destination,
ValidatorCoordinate underAttack, XiangqiColor c){
board.movePiece(source, destination, c);
boolean blocked = !underAttack(underAttack, c);
board.movePiece(destination, source, c);
return blocked;
}
movePiece()方法肯定会在HashMap中移动片段(此时已经过彻底测试)
非常感谢任何帮助。
谢谢!
编辑:为了澄清,这种通用方法一直有效,直到我将移动抽象为另一种方法( tryBlock )。以前, tryBlock 的内容都在循环内部,并且没有抛出任何异常。这也是我关注这一点的原因,对我而言,它本应该抛出异常。
答案 0 :(得分:0)
您是否考虑过从HashMap切换到ConcurrentHashMap?后者允许对映射进行并行读取,并避免许多并发异常,这些异常异常通常是由共享映射的线程代码导致的(不完全是您描述的内容)。
正如评论者指出的那样,即使您反转了内容(例如添加/删除或删除/添加),您也可能会遇到并发异常。
答案 1 :(得分:0)
出现问题是因为您正在迭代地图的键集,并在循环中修改地图。地图不会跟踪您将其重新置于同一状态的事实。对映射的任何结构修改都会使现有迭代器无效。
相反,迭代密钥集的副本,例如将元素放入List
以确保密钥以相同的顺序迭代,而不是直接使用密钥集:
for (ValidatorCoordinate v : new ArrayList<>(keys)) {
// ...
}
这是与键集完全独立的集合,因此对映射的修改对迭代器没有影响。
答案 2 :(得分:0)
最简单的答案是调整tryBlock(..)的实现,这样你只有在没有被阻止的情况下才会移动[而不是在被阻止的情况下尝试撤消移动]
private boolean tryBlock(ValidatorCoordinate source,
ValidatorCoordinate destination,
ValidatorCoordinate underAttack, XiangqiColor c){
boolean blocked = !underAttack(underAttack, c);
if (!blocked)
board.movePiece(source, destination, c);
return blocked;
}