2009-12-22 88 views
2

這是我的代碼,構建一個可能的城市之旅Locale l(這不是最佳的,它只是讓我的AI搜索領先)。不確定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,除remove之外的確有add方法。

  4. 不使用迭代器在所有的,只是訪問由指數的ArrayList(你已經做在其他地方無論如何)

另外,還可以有很多類型轉換的做掉,通過指定迭代器的類型(與列表相同)。

+0

我一看到異常就想到了1&2 我的代碼大致是在每對城市之間插入最好的城市,直到所有的城市都在參觀,因此每個城市都需要在自己身後才能完成隨着新配對的形成而增加 看起來,3我是我的最佳選擇,我現在就開始修復。 雖然SO回到我身邊,但我想到了一個可能的數字5,它將採用main while循環的內容並將其變爲方法,並遞歸解決此問題,從而不使用迭代器,並希望避免異常 感謝所有幫助^ _^ – Gwilym 2009-12-22 13:25:08

+0

+1。第一句話是重要的一句話...... – Jared 2009-12-22 15:23:09

0

javadoc爲ArrayList的:

的迭代器通過此類的iterator和的ListIterator方法返回的是快速失敗的:如果列表在任何時間從結構上修改創建迭代器之後,以任何方式,除了通過迭代器自己的remove或add方法,迭代器將拋出一個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); 
       } 

這是不允許修改的列表
摘錄。度Acc與JavaDoc http://java.sun.com/j2se/1.4.2/docs/api/java/util/ConcurrentModificationException.html

此異常可能由已經檢測到對象的併發 修改當這樣的修改 不允許 方法被拋出。對於 示例,通常不會讓一個線程修改 集合,而另一個線程則通過 迭代它。一般而言,在這些情況下迭代結果 未定義。如果 檢測到此行爲,則某些 迭代器實現(包括 JRE提供的所有集合 實現中的那些實現) 可能會選擇拋出此異常。這樣做的迭代器 被稱爲快速失敗 迭代器,因爲它們很快就會失敗,並且會在未來某個未確定的時間冒險 任意的,非確定性行爲 。

1

您可以輕鬆地解決此使用索引變量,而不是迭代器:

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

但是,你會發現,插入元素你迭代名單提出了一些棘手的問題。 Iterator引發ConcurrentModificationException是有原因的,因爲繼續迭代的邏輯沒有很好的定義。如果在索引位置之前插入一個元素,那麼索引不再指向同一個「當前」元素,並且您需要將索引增加兩個以找到下一個元素。如果你之後插入,除停止條件外(除tour.size()將正確增長以外沒有任何變化)。如果你在不同的位置進行多次插入/刪除操作,很難保持跟蹤...

我有一種感覺,你的算法cuold也被簡化了,雖然它不完全清楚它應該做什麼。

+0

在插入內容時如何處理索引的問題已經非常令人滿意^ _ ^,我的代碼現在可以很好地工作(在大約10秒內獲得最佳解決方案的12%),但它非常大而且很難看。一個非常不穩定的算法,但即時通過我曾經教導過我的程序員的一些教訓,「如果你不確定如何編寫代碼,那麼編寫代碼很糟糕,然後一點一點地改進它,直到你編碼得很好」 – Gwilym 2009-12-22 18:07:18

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); 
    } 

} 

}