2017-02-03 14 views
0

Я пытался под кодом ниже.Модифицируя 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 иногда и время от времени работает успешно.

Что я не понимаю, так как существует два разных метода, каждый из которых содержит один поток. Они будут выполняться один за другим. Когда один поток заканчивает изменение списка, Thread 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

Вы начинаете два потока и не выполняете дальнейших синхронизаций.

Иногда оба потока будут работать в одно и то же время, и вы получите CME. В других случаях первый поток завершается до того, как второй поток начнет выполняться. В этом сценарии не будет CME.

Причина, по которой вы получаете вариацию, вполне может опуститься до таких вещей, как нагрузка на вашу систему. Или это просто может быть связано с тем, что планировщик потоков не является детерминированным.

Ваши потоки фактически выполняют небольшое количество работ по сравнению с накладными расходами на создание/запуск потока. Поэтому неудивительно, что один из них может быстро вернуться из своего метода run().

+0

Это было бы так, если бы я называл их «Thread obj = new Thread(); obj.start(); Thread obj2 = new Thread(); obj2.start();» Но это два разных метода. Они будут называться один за другим. Не так ли? –

+0

Да. Они есть. Но внимательно прочитайте javadocs для 'start()'. Они не гарантируют, что дочерний поток будет * запущен * к тому времени, когда вызов 'start()' будет возвращен вызывающему абоненту. Фактически, не имеет значения, что два 'start()' вызова имеют разные методы. –