2017-02-03 3 views
0

私は以下のコードを試していました。1つのスレッドでArrayListを変更して別のスレッドで反復している間にConcurrentModificationExceptionをスローしています

public class IteratorFailFastTest { 

    private List<Integer> list = new ArrayList<>(); 

    public IteratorFailFastTest() { 
     for (int i = 0; i < 10; i++) { 
      list.add(i); 
     } 
    } 

    public void runUpdateThread() { 
     Thread thread2 = new Thread(new Runnable() { 

      public void run() { 
       for (int i = 10; i < 20; i++) { 
        list.add(i); 

       } 
      } 
     }); 

     thread2.start(); 
    } 


    public void runIteratorThread() { 
     Thread thread1 = new Thread(new Runnable() { 

      public void run() { 
       ListIterator<Integer> iterator = list.listIterator(); 

       while (iterator.hasNext()) { 
       Integer number = iterator.next(); 
       System.out.println(number); 
       } 

      } 
     }); 

     thread1.start(); 
    } 
    public static void main(String[] args) { 
     // TODO Auto-generated method stub 
     IteratorFailFastTest tester = new IteratorFailFastTest(); 

     tester.runIteratorThread(); 
     tester.runUpdateThread(); 
    } 

} 

時にはConcurrentModificationExceptionがスローされ、正常に実行されています。

私は理解できないことは、それぞれに1つのスレッドを含む2つの異なるメソッドがあるからです。彼らは一つずつ実行されます。 1つのスレッドがリストの変更を完了すると、スレッド2は反復を開始します。

私はこのリンク(Why no ConcurrentModificationException when one thread iterating (using Iterator) and other thread modifying same copy of non-thread-safe ArrayList)も参照していますが、別のシナリオです。

なぜこの例外がスローされるのですか?それはスレッドのためですか?

誰かが説明できますか?

+0

コード/記事にリンクしないでください。あなたの質問を編集して実際のコード断片を含める。 – Bohemian

+0

@Bohemian:私は投稿を編集しました。 –

+0

CMEは必要ありません。イテレータは作成されていますが使用されていません。 – Bohemian

答えて

0

2つのスレッドを開始していて、それ以上の同期は実行していません。

時には両方のスレッドが同時に実行され、CMEが取得されることがあります。それ以外のときは、第1のスレッドは、第2のスレッドが実際に実行を開始する前に終了します。そのシナリオではCMEを取得しません。

バリエーションを取得する理由は、システムの負荷のようなものになる可能性があります。または、スレッドスケジューラが非決定論的であるという事実に単純に陥る可能性があります。

あなたのスレッドは、スレッドの作成/開始のオーバーヘッドに比べて、実際にはほんのわずかです。したがって、彼らのうちの1人が非常に迅速にrun()メソッドから戻ることができることは驚くべきことではありません。

+0

私はそれらを 'Thread obj = new Thread();'のように呼んでいたのです。 obj.start();スレッドobj2 =新しいスレッド(); obj2.start(); 'しかし、これらは2つの異なる方法です。彼らは一つずつ呼び出されます。彼らじゃない? –

+0

はい。彼らです。しかし、javadocを 'start()'で慎重に読んでください。実際には、2つの 'start()'呼び出しが異なるメソッドにあることは無関係です。子スレッドは、 'start()'呼び出しが呼び出し側に返るまでに*実行されていることを保証しません。 –

関連する問題