Модифицируя 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, а иногда и успешно.
Чего я не понимаю, так это 2 разных метода, каждый из которых содержит один поток. Они будут выполнять по одному. Когда один поток завершит изменение списка, поток 2 начнет итерацию.
Я также ссылался на эту ссылку ( почему нет ConcurrentModificationException, когда один поток повторяется (используя Iterator), а другой поток изменяет одну и ту же копию не-поточно-безопасного ArrayList), но это другой сценарий.
Так почему же это исключение? Это из-за потоков?
Может кто-нибудь объяснить?
1 ответ
Вы запускаете два потока, а затем не выполняете дальнейшую синхронизацию.
Иногда оба потока будут работать одновременно, и вы получите CME. В других случаях первый поток завершается до того, как второй поток фактически начнет выполняться. В этом случае не получит CME.
Причина, по которой вы получаете этот вариант, может быть связана с нагрузкой на вашу систему. Или это может быть просто из-за того, что планировщик потока недетерминирован.
Ваши потоки фактически выполняют небольшую работу по сравнению с накладными расходами на создание / запуск потока. Поэтому неудивительно, что один из них может вернуться из своего run()
метод очень быстро.