2017-10-08 76 views
2

我有以下代碼兩個迭代器拋出ConcurrentModificationException

public static void main(String[] args) { 

     List<String> list = new ArrayList<>(); 
     Arrays.stream("hello how are you".split(" ")).forEach(s -> list.add(s)); 

     Iterator<String> it = list.iterator(); 
     ListIterator<String> lit = list.listIterator(); 

     while (it.hasNext()) { 
      String s = it.next(); 
      if (s.startsWith("a")) { 
       it.remove(); 
      } else { 
       System.out.println(s); 
      } 
     } 

     System.out.println(list); 

     // {here} 

     while (lit.hasNext()) { 
      String s = lit.next(); 
      if (s.startsWith("a")) { 
       lit.set("1111" + s); 
      } else { 
       System.out.println(s); 
      } 
     } 

     System.out.println(list); 
} 

這裏,通過Iterator迭代後,我試圖通過ListIterator進行迭代。但是代碼會拋出ConcurrentModificationException。我只在Iterator完成後才使用ListIterator進行修改,但爲什麼我會得到這個異常。

當我在位於{here}處的ListIterator初始化代碼時,代碼完美運行。

  1. 列表被兩個線程同時修改時,是不是ConcurrentModificationException
  2. 是否初始化迭代器,在列表上創建一個鎖?如果是,那麼Java爲什麼讓我們初始化一個Iterator,然後它已經被另一個Iterator初始化了?

回答

2

當列表被兩個線程同時修改時,是不是引發了ConcurrentModificationException異常?

不一定。 ConcurrentModificationException表示在創建Iterator之後,列表在結構上發生了變化(除了Iterator自己的remove方法)。這可能是由於多個線程使用相同的列表,或者可能是由於嘗試刪除每個循環內的ArrayList內的項而不使用Iterator

是否初始化迭代器,在列表上創建一個鎖?

不,沒有鎖。創建Iterator時,它會記錄ArrayListmodCount(列表狀態的粗略表示,在每次結構更改時遞增)。如果迭代器檢測到List的modcount不是由其自身方法引起的更改,則會引發異常。

由於在實例化和使用的第二個迭代器之間對列表進行了結構更改,您正在從第二個迭代器中獲得異常。

爲什麼Java讓我們在Iterator已經被另一個Iterator初始化之後初始化一個Iterator?

ArrayList不會跟蹤它創建的所有迭代器或其狀態。這樣做會使執行過程複雜化。 modCount的方法並不完美,有點粗糙,但它很簡單,並確定了許多真正的錯誤。

+0

那麼這是否意味着沒有兩個迭代器可以在同一個列表上作用? – v1shnu

+0

你可以讓兩個迭代器同時迭代同一個列表。如果他們不添加或刪除元素,則不會拋出異常。 –

+0

@PaulBoddington爲什麼我們不能同時迭代同一個列表時執行更新操作。迭代器在迭代時是否保留自己的副本,並在所有迭代結束時更新最終列表,或者每遍更新原始列表? –

1

您必須在使用第一個迭代器後加載第二個迭代器。否則,第二個迭代器「認爲」列表沒有被改變,但實際上它已經做了。因爲列表發生了變化,所以第二個迭代器的反應類似於「等待一分鐘,不應該出現/消失」並引發ConcurrentModificationException

它讓你在任何時候初始化迭代器。如果不更改內容,則可能會更好,並且因爲沒有任何更改,您不會獲得ConcurrentModificationException

1

當您嘗試使用無效的迭代器時可能會引發ConcurrentModificationException - 無論何時創建迭代器,然後從不同的訪問點修改基礎集合,都可能發生這種情況。在這裏,​​3210被初始化,然後通過it修改列表,所以其無效,這解釋了例外。

0

ListIterator拋出ConcurrentModificationException它在創建後在列表中存在修改。在您的代碼中,您同時創建了Iterator和ListIterator,稍後您將從列表中刪除導致ConcurrentModificationException的某些內容。

爲了避免這種情況,將您的代碼更改爲低於1。您只需在迭代器的操作之後移動ListIterator初始化。

public static void main(String[] args) { 

    List<String> list = new ArrayList<>(); 
    Arrays.stream("hello how are you".split(" ")).forEach(s -> list.add(s)); 

    Iterator<String> it = list.iterator(); 

    while (it.hasNext()) { 
     String s = it.next(); 
     if (s.startsWith("a")) { 
      it.remove(); 
     } else { 
      System.out.println(s); 
     } 
    } 

    System.out.println(list); 

    ListIterator<String> lit = list.listIterator(); 

    while (lit.hasNext()) { 
     String s = lit.next(); 
     if (s.startsWith("a")) { 
      lit.set("1111" + s); 
     } else { 
      System.out.println(s); 
     } 
    } 

    System.out.println(list); 
} 
相關問題