我一直得到java.util.concurrentmodificationexception ..如何解决这个问题?

时间:2012-01-03 16:29:27

标签: java concurrentmodification

我一直在研究这段代码。这是我想要发生的伪代码:

a.check如果部分(列表)大小为0 b。如果部分大小为0,则通过调用sections.add(newSection)
自动将学生注册到该部分 c。如果章节大小不为零,请检查与时间表的冲突 d。如果没有冲突,则通过调用sections.add(newSection)
将学生注册到该部分 e.else什么都不做

Java不断向我抛出“java.util.concurrentmodificationexception”错误。我知道,我不应该在遍历列表时改变ArrayList的大小,因为它会修改迭代器。还有另一种解决方法吗? :d

非常感谢。 非常感谢您的帮助。 :)

 public String enrollsTo(Section newSection){


        StringBuffer result = new StringBuffer();

        String resultNegative = "Failed to enroll in this section.";
        String resultPositive = "Successfully enrolled in section: " + newSection.getSectionName() + ".";

        int previousSectionSize = sections.size();

        if(this.sections.isEmpty()){
            this.sections.add(newSection);
            result.append(resultPositive);
        }else{
            for(Iterator<Section> iterator = sections.iterator(); iterator.hasNext() ; ){
                Section thisSection = iterator.next();

                if(thisSection.conflictsDayWith(newSection)==false &&
                    thisSection.conflictsTimeWith(newSection)==false){
                    this.sections.add(newSection);  //<-- i believe the problem lies here.
                    result.append(resultPositive);
                }
            }
        }
//      if(this.sections.size() == previousSectionSize){
//          result.append(resultNegative);
//      }
        return result.toString();
    }

6 个答案:

答案 0 :(得分:1)

不要在for循环中执行sections.add(newSection),因为这是对当前正在迭代的集合的修改。

另外,在决定是否添加newSection之前,您不想检查所有部分吗?也许是这样的:

boolean conflict = false;
for (...) {
  if (/* check for conflict */) {
    conflict = true;
    break;
  }
}
if (!conflict) {
  sections.add(newSection);
}

答案 1 :(得分:0)

来自ConcurrentModificationException的javadoc(我的重点):

  

检测到并发的方法可能抛出此异常   在不允许进行此类修改时修改对象。

     

例如,一个线程通常不允许修改   一个集合,而另一个线程正在迭代它。一般来说,   在这些情况下,迭代的结果是不确定的。   一些迭代器实现(包括所有通用的实现)   由JRE提供的目的集合实现可以选择   如果检测到此行为,则抛出此异常。那个迭代器   这被称为故障快速迭代器,因为它们很快就会失败   干净利落,而不是冒着任意的,非确定性的行为冒险   未来不确定的时间。

     

请注意,此异常并不总是表示对象具有   由另一个线程同时修改。如果是单线程   发出一系列违反合同的方法调用   一个对象,该对象可能抛出此异常。 例如,如果是   线程在迭代时直接修改集合   使用失败快速迭代器进行集合,迭代器将抛出此异常   异常。

     

请注意,通常情况下无法保证快速失败的行为   说话,在场的情况下不可能做出任何硬性保证   不同步的并发修改。失败快速操作投掷   ConcurrentModificationException是尽力而为的。因此,它   编写一个依赖于此异常的程序是错误的   它的正确性:应该只使用ConcurrentModificationException   检测错误。

潜在的解决方案:不是直接添加到您要重复的列表中,而是添加到临时列表中,然后在您完成迭代后,执行addAll()

答案 2 :(得分:0)

迭代收集时,您无法修改它。抛出异常的行this.sections.add(newSection);。您可能需要使用一些布尔标记来检查条件

if(thisSection.conflictsDayWith(newSection)==false &&
                    thisSection.conflictsTimeWith(newSection)==false)

如果您的布尔标记为真,则在for循环之后,您可以编写

 this.sections.add(newSection);  
                    result.append(resultPositive);

答案 3 :(得分:0)

你的假设是正确的,

 this.sections.add(newSection);  

绝对是您问题的根源。

最简单的解决方案:有一个表示该部分可用性的布尔值。首先假设它可用。如果迭代器中存在任何冲突,请将其设置为false。在迭代器之后,如果该部分可用,则添加该部分(布尔值为true)。

答案 4 :(得分:0)

当您在迭代其元素时修改集合时,通常会发生ConcurrentModificationExceptions。请阅读this tutorial以获取更多详细信息以及此旧帖子Why does it.next() throw java.util.ConcurrentModificationException?

答案 5 :(得分:0)

我同意@sudocode你不想在每次找到一个不冲突的部分时添加newSection。我会想到,当你在调试器中单步执行代码时,这将是显而易见的。 ;)

BTW另一种(更加模糊的)没有标志的方式

CHECK: {
  for (...) {
    if (/* check for conflict */) 
      break CHECK;
  }

  sections.add(newSection);
}