[英]ConcurrentModificationException in single Threaded unmodifiableList
[英]ConcurrentModificationException on single-threaded code
编辑:嗯,我觉得很害羞。 我在看错误的构造函数。 根据 Kal 的回答,被调用的真正构造函数(见下文) - 违反了 foreach 循环的并发规则。
无论如何,感谢您的帮助。 它仍然可以帮助我修复代码的实际错误。
全部
我是一个相当新的 Java 程序员,我才刚刚开始掌握该语言的基本句柄。 我目前正在使用对话参与者系统,但首先尝试使我们的系统对逻辑术语的表示符合规范。 我快完成了,但遇到了以下错误:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at com.Term.<init>(Term.java:97)
at com.Term.substituteVariables(Term.java:251)
at com.Term.substituteVariables(Term.java:247)
at com.Term.substituteVariables(Term.java:247)
at com.TermPredTestArch.main(TermPredTestArch.java:40)
有问题的方法,substituteVariables,基本上是一个复制构造函数,稍作修改:它接受一个 map 绑定,并递归遍历它被调用的 Term Object,一路找到变量并将它们换成它们实例化。 奇怪的是,昨晚我离开时它似乎还在工作(虽然我没有进行广泛的测试),但现在拒绝玩得很好; 我没有做任何实质性的修改。
相关代码如下(232-252行):
232 /** Returns a new Term with the appropriate bindings substituted */
233 public Term substituteVariables(Map<Variable, Symbol> bindings) {
234 ArrayList<Symbol> args = this.getArgs();
235 ArrayList<Symbol> newArgs = new ArrayList<Symbol>();
236 Set<Variable> vars = this.getVars();
237 Set<Variable> bindingKeys = bindings.keySet();
238 for(Symbol s: args) {
239 // if s is a Variable, check to see if it has a substituion, and
240 // if so, swap it out
241 if(s instanceof Variable) {
242 if(bindingKeys.contains(s)) newArgs.add(bindings.get(s));
243 else newArgs.add(s);
244 // if s is a Term, add it and recursively substitute any variables
245 // it has within the current set of bindings
246 } else if(s instanceof Term) {
247 newArgs.add(((Term) s).substituteVariables(bindings));
248 // if s is just a symbol, simply add it to the args
249 } else newArgs.add(s);
250 }
251 return new Term(this.getName(), newArgs);
252 }
编辑:这是 Term 的构造函数:
public Term(String n, ArrayList<Symbol> a) {
super(n);
args = a;
HashSet<Variable> varsToAdd = new HashSet<Variable>();
for(Symbol s: a) parseArg(s.toString());
}
那是被调用的-actual-构造函数,而不是我认为被调用的构造函数。 根据 Kal 的回答,这确实违反了 foreach 循环并发规则。
根据我已经完成的研究,我知道 ConcurrentModificationException 通常是由多个线程在没有同步的情况下同时迭代/修改集合引起的,但是我在这里没有故意的并行性,也没有在 class 或使用它的测试代码中的其他任何地方. 否则,我不完全确定。 class 的 javadoc 提到它也可能是由迭代器同时迭代和修改集合引起的,但我认为我也没有这样做; 我只是观察迭代的集合并使用其中的信息来构建另一个集合。 这是否也违反了并发规则?
任何你们都可以提供的指针将不胜感激。 对于任何严重违反 Java 礼仪或风格的行为,我也会先发制人地道歉(也请随时指出这些!)。
谢谢
当您修改 ArrayList 并使用 for 循环遍历它时,会发生 ConcurrentModificationException。
正确执行此操作的方法是使用迭代器添加/删除方法。
这是来自 API 的相关文档——
此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对 list 进行结构修改,除了通过迭代器自己的 remove 或 add 方法之外的任何方式,迭代器将抛出 ConcurrentModificationException。 因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。
newArgs.add(((Term) s).substituteVariables(bindings));
因此,在这部分代码中,您会遇到错误; 就像 Kal 说的那样,它发生在您编辑您正在迭代的 ArrayList 时。 修复问题更改
for(Symbol s: args) {
至
for (int i = 0; i < args.size(); i++) {
Symbol s = args.get(i);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.