2009-12-22 1 views
2

Это мой код, чтобы построить возможный тур по городам в Locale l (это не оптимально, это просто дать мой ИИ поиск в начале).не уверен в причине ConcurrentModificationException

Я получаю ConcurrentModificationException, что, насколько мне известно, происходит, когда более одной части кода обращается к переменной/коллекции и пытается ее модифицировать. Вызывая этот код, чтобы получить несчастные:

final void checkForComodification() { 
    if (modCount != expectedModCount) 
     throw new ConcurrentModificationException(); 
} 

я изменить его, как я добавляю элемент в, но как итератор не метод для добавления (только удаление) Я использую метод коллекции.

Итак, мои вопросы:

  1. Является ли мое добавление элемента, что вызывает проблему?
  2. Если это так, как я могу добавить его правильно, так что modCount верен, и я не получаю ConcurrentModificationException?

Полный метод ниже, с комментарием на линии, где ConcurrentModificationException происходит:

public void construct() { 
    tour = new ArrayList(); 
    ArrayList<City> lcl = new ArrayList(l.getCitys()); 

    tour.add(lcl.remove(0)); 
    tour.add(lcl.remove(1)); 

    while (!this.tourComplete()) { 
     System.out.println(tour.size()); 
     Iterator tourit = tour.iterator(); 
     City g1 = (City) tourit.next(); 
     City g2 = (City) tour.get(lcl.indexOf(g1)+1); 

     int gapDist = l.distanceBetweenCitys(g1, g2); 

     while (tourit.hasNext()) { 
      City C = null; 
      int best = Integer.MAX_VALUE; 

      for (Iterator lclit = lcl.iterator(); lclit.hasNext();) { 
       City c = (City) lclit.next(); 
       int avg = (l.distanceBetweenCitys(g1,c) + 
          l.distanceBetweenCitys(g2, c))/2 ; 

       if ((avg<gapDist) && (avg<best)) { 
        C = c; 
        best = avg; 
       } 
      } 

      if (C != null) { 
       assert(best == Integer.MAX_VALUE); 
       City A = tour.get(0); 
       City Z = tour.get(tour.size()-1); 

       boolean begin = true; 

       for (Iterator lclit = lcl.iterator(); lclit.hasNext();) { 
        City c = (City) lclit.next(); 
        int dist = l.distanceBetweenCitys(A,c); 

        if (dist<best) { 
         begin = true; 
         C = c; 
         best = dist; 
        } 
       } 

       for (Iterator lclit = lcl.iterator(); lclit.hasNext();) { 
        City c = (City) lclit.next(); 
        int dist = l.distanceBetweenCitys(Z,c); 

        if (dist<best) { 
         begin = false; 
         C = c; 
         best = dist; 
        } 
       } 

       if (begin) { 
        // one of these is causing the problem 
        tour.add(0,C); 
       } 
       else { 
        // one of these is causing the problem 
        tour.add(C); 
       } 
      } 
      else { 
       // one of these is causing the problem 
       tour.add(tour.indexOf(g2),C); 
      } 

      g1 = (City) tourit.next(); // this is where it all goes wrong 
      g2 = (City) tour.get(lcl.indexOf(g1)+1); 
      gapDist = l.distanceBetweenCitys(g1, g2); 
     } 
    } 
} 

ответ

5

Вы не можете изменить основную коллекцию, используя итератор (кроме как через сам итератора).

Я не пошел через алгоритм (вы, кажется, хотите вставить в произвольных позициях, которые могли бы быть сложно), но, возможно, вы можете сделать одно из следующих действий:

  1. собрать все, что вы хотите добавьте во вторую коллекцию и сделайте addAll после того, как вы закончите.

  2. Итерации над копией коллекции.

  3. Используйте ListIterator, который имеет метод add в дополнение к remove.

  4. Не использовать итератор на всех, и просто получить доступ к ArrayList по индексу (который вы уже делаете в других местах, так или иначе)

Кроме того, вы можете сделать прочь с большим количеством приведения типов, указав тип итератора (аналогично тому, как вы делали со списком).

+0

Я подумал о 1 и 2, как только увидел исключение Мое, что мой код делает грубо, заключается в том, чтобы вставить лучший город между каждой парой городов, пока все города не окажутся в туре, поэтому ему нужно перебраться через себя после каждого города добавляется по мере создания новых пар Казалось бы, что 3 идентификатора мой лучший вариант, Иль теперь спустится к исправлению. Пока SO возвращался ко мне, я подумал о возможном числе 5, которое должно было бы взять содержимое основного цикла while и превратить его в метод, и решить это рекурсивно, не используя итератор, и, надеюсь, избегаем исключения спасибо за помощь^_^ – Gwilym

+0

+1. Первое предложение является важным ... – Jared

0

С javadoc для ArrayList:

Итераторов возвращенного итератора и ListIterator методами этого класса являются отказоустойчивость быстро: если список конструктивно изменен в любое время после того, как итератор создается, в любом случае, кроме через собственные методы удаления или добавления итератора, итератор будет вызывать исключение ConcurrentModificationException. Таким образом, перед лицом одновременной модификации итератор быстро и чисто, а не рискует произвольным, недетерминированным поведением в неопределенное время в будущем.

1

Внутри итератор петли вы пытаетесь изменить список
Отрывок из кода

if (begin) { 
        // one of these is causing the problem 
        tour.add(0,C); 
       } 
       else { 
        // one of these is causing the problem 
        tour.add(C); 
       } 

Это не допустимо. Точность в JavaDoc http://java.sun.com/j2se/1.4.2/docs/api/java/util/ConcurrentModificationException.html

Это исключение может быть брошено методов, которые обнаруженными одновременного модификации объекта, когда такое модификации не допускается. Например, для обычно нет для одной нити для изменения коллекции , а другая - , итерации по ней. В общем случае результаты итерации не определены при данных обстоятельствах. Некоторые Реализации Iterator (в том числе тех из всех сборов, что реализованы JRE) могут выбрать это исключение, если обнаружено это поведение. Итераторы , которые делают это так же быстродействующими итераторами , так как они не работают быстро и чисто, а скорее рискуют произвольным, недетерминированным поведением в неопределенное время в будущем.

1

Вы можете легко обойти эту проблему с помощью индексной переменной вместо итератора:

int i = 0; 
while (i < tour.size()) { 
    .... 
    i++; 
} 

Однако, можно заметить, что вставка элементов в список вы Перебор поднимает некоторые каверзные вопросы. Существует причина, по которой Iterator создает исключение ConcurrentModificationException, поскольку логика продолжения итерации не определена. Если вы вставляете элемент перед своей позицией индекса, то индекс больше не указывает на тот же «текущий» элемент, и вам нужно увеличить индекс на два, чтобы найти следующий элемент. Если вы вставляете после, то ничего не меняется, кроме условия остановки (но tour.size() будет расти правильно, так что все в порядке). Если вы делаете несколько вставок/удалений в разных положениях, становится трудно отследить ...

У меня есть чувство, что ваш алгоритм cuold также будет упрощен, хотя мне не совсем ясно, что он должен делать ,

+0

что делать с индексом при вставке материала было очень интересно^_ ^, мой код теперь работает и очень хорошо (получает в пределах 12% от оптимального решения примерно за 10 секунд), но очень большой и уродливый его очень неустойчивый алгоритм, но я собираюсь с тем, что программист, которого я уважаю много раз, когда-то научил меня, «если вы не знаете, как его правильно закодировать, тогда немного улучшите его, пока вы его не закодировали» – Gwilym

0

Это мой уродливый, но теперь рабочий код для тех, кто хочет увидеть, как я получил его в конце концов, я намерен довольно это совсем немного, но для момента им доволен тем, что работает

public void construct() 
{ 
tour = new ArrayList(); 
ArrayList<City> lcl = new ArrayList(l.getCitys()); 

tour.add(lcl.remove(0)); 
tour.add(lcl.remove(1)); 
tour.add(lcl.remove(2)); 

while (!this.tourComplete()) 
{ 

System.out.println(tour.size()); 
ListIterator<City> tourit = tour.listIterator(); 
City g1 = (City) tourit.next(); 
City g2 = (City) tour.get(tour.indexOf(g1)+1); 

int gapDist = l.distanceBetweenCitys(g1, g2); 

    while ((tourit.nextIndex()!=tour.size()-1) && !this.tourComplete()) 
    { 
    System.out.println("x"); 
    City C = null; 
    int best = Integer.MAX_VALUE; 

     for (ListIterator<City> lclit = lcl.listIterator(); lclit.hasNext();) 
     { 
     City c = (City) lclit.next(); 
     int avg = (l.distanceBetweenCitys(g1,c)+ l.distanceBetweenCitys(g2, c))/2 ; 

     if ((avg<gapDist) && (avg<best)) 
     { 
     C=c; 
     best=avg; 
     } 

     } 

    if (C==null) 
    { 
    System.out.println("C null"); 
     assert(best==Integer.MAX_VALUE); 
     City A = tour.get(0); 
     City Z = tour.get(tour.size()-1); 

     boolean begin = true; 

     for (ListIterator<City> lclit = lcl.listIterator(); lclit.hasNext();) 
     { 
      City c = (City) lclit.next(); 
      int dist = l.distanceBetweenCitys(A,c); 

      if (dist<best) 
      { 
      begin=true; 
      C=c; 
      best=dist; 
      } 

     } 

     for (ListIterator<City> lclit = lcl.listIterator(); lclit.hasNext();) 
     { 
      City c = (City) lclit.next(); 
      int dist = l.distanceBetweenCitys(Z,c); 

      if (dist<best) 
      { 
      begin=false; 
      C=c; 
      best=dist; 
      } 

     } 

     if(begin) 
     { 
     System.out.println("add at begining"); 
     System.out.println(this.TourtoString()); 
     // add in at 0 

      int itpos = tourit.nextIndex(); 
      //move iterator to 0 
      while (tourit.hasPrevious()) 
      { 
      tourit.previous(); 
      } 

      lcl.remove(C); 
      // add in C 
      tourit.add(C); 

      // move iterator back 
      while(tourit.nextIndex()!=(itpos+1)) 
      { 
      tourit.next(); 
      } 
     System.out.println(this.TourtoString()); 
     } 
     else 
     { 
     // add in at end 
      int itpos = tourit.nextIndex(); 
      //move iterator to end 
      while (tourit.hasNext()) 
      { 
      tourit.next(); 
      } 

      lcl.remove(C); 
      // add in C 
      tourit.add(C); 

      // move iterator back 
      while(tourit.nextIndex()!=itpos) 
      { 
      tourit.previous(); 
      } 
     } 

    } 
    else 
    { 
    System.out.println("C not null"); 

    // add in at g2 
    int moveto = tour.indexOf(g2); 
    int itpos = tourit.nextIndex(); 

    System.out.println("add at: "+ moveto); 
    System.out.println(this.TourtoString()); 


    if (itpos>=moveto) 
    { 
    itpos++; 
    } 

    //move iterator to 0 
    while (tourit.hasPrevious()) 
    { 
    tourit.previous(); 
    } 

    // move iterator to insertion location 
    while (tourit.nextIndex()!=moveto) 
    { 
    tourit.next(); 
    } 

    lcl.remove(C); 
    // add in C 
    tourit.add(C); 

    //move iterator to 0 
    while (tourit.hasPrevious()) 
    { 
    tourit.previous(); 
    } 


    // move iterator back 
    while(tourit.nextIndex()!=itpos) 
    { 
    tourit.next(); 
    } 

    System.out.println(this.TourtoString()); 
    } 


    g1 = (City) tourit.next(); 
    g2 = (City) tour.get(tour.indexOf(g1)+1); 
    gapDist = l.distanceBetweenCitys(g1, g2); 
    } 

} 

} 
Смежные вопросы