Concurrentmodificationexception java когда возникает

Избавляемся от ConcurrentModificationException

Как известно, ConcurrentModificationException к многопоточности никакого отношения не имеет. Возникает эта гадость, когда мы пытаемся модифицировать коллекцию во время итерирования по ней. Как обычно, это имеет исторические корни: коллекции и итераторы появились в Java 1.2, в те времена избежать явного использования итератора при обходе коллекции было никак нельзя, так что предложение менять коллекцию посредством методов итератора не выглядело совсем ужасным:

Не, всё же выглядело. Но никаких других вариантов не было. Позже в пятой джаве появляется цикл foreach, и использование итераторов становится преимущественно неявным:

«Ишь чего захотели! Юзайте явные итераторы, дорогие кастомеры, и не выделывайтесь» — наверное что-то такое думали разработчики джава платформы работая над пятеркой.

В шестой джаве появляется пакет конкаренси. Теперь можно cделать так:

И получить set который не кидается ConcurrentModificationException-ами. Но опять же счастье не совсем полное:

  1. Oбычно многопоточность нам вовсе не нужна
  2. Не подерживаются null ни в качестве элементов, ни ключей, ни значений. Да и ладно, честно сказать.
  3. Порядок элементов не определён и может меняться — вот это гораздо хуже. Т.е. если мы бежим по элементам и ведём некий подсчёт с потерей точности, то нас могут поджидать неприятные сюрпризы и разные результаты на одних и тех же наборах данных, что, скажем, не всегда хорошо. Так же бывают задачи, где желательно сохранить именно изначальный порядок данных. Ну и вот такие штуки тоже имеют место быть:
  1. В рамках одного треда можно добавлять и удалять элементы в любой момент без всяких эксепшенов. И конечно же за константное время.
  2. Можно хранить null-ы, если вдруг хочется.
  3. Элементы обходятся в том порядке в котором были добавлены.
  1. Удаляя элемент мы не будем обнулять ссылку на следующий, т. е. eсли итератор стоит на данном элементе, то он сможет пройти дальше.
  2. В конце списка поместим фэйковый элемент, который превращается в настоящий когда в список что-нибудь добавляют. Т.е. даже добравшись до конца списка итератор не упирается в null и может продолжить работу если в коллекции появляется новый элемент. Далее в коде этот фейковый элемент называется placeholder.

  1. В начале у нас есть элементы A, B, C, D.
  2. Затем элементы C и D удаляются.
  3. Добавляется новый элемент E.

Ну и для константного времени доступа нам, очевидно, нужен хэшмап:

Теперь можно делать так:

Понятно, что аналогично можно сконструировать и LinkedMap. Вот в общем-то и всё, ещё один велосипед готов. Почему подобным образом не доработали библиотечные LinkedHashMap и LinkedHashSet? Кто знает, возможно чтобы джависты завидовали джаваскриптистам.

Как бороться с ConcurrentModificationException в Java?

Одной из распространенных проблем при удалении элементов из ArrayList в Java является исключение ConcurrentModificationException. Если вы используете классический цикл for с индексом или расширенный цикл for и пытаетесь удалить элемент из ArrayList с помощью метода remove() , вы получите oncurrentModificationException C oncurrentModificationException но если вы используете метод удаления Iterator или метод ListIterator’s
метод remove() , тогда вы не получите эту ошибку и не сможете удалить элемент. Это неписанное правило в Java, что при циклическом просмотре списка не следует add() элементы add() или remove() пока коллекция не поддерживает отказоустойчивый итератор, например, CopyOnWriteArrayList , которые работают с копией списка, а не с оригинальным списком.

Основная проблема с этой ошибкой состоит в том, что это смущает разработчика, что список изменяется несколькими потоками, и именно поэтому Java выдает эту ошибку, это не так. Большую часть времени
ConcurrentModificationException приходит даже без нескольких потоков, изменяющих список.

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

В этой статье я объясню эту ошибку, и мы приведем множество примеров кода, чтобы воспроизвести этот код даже в одном потоке, и узнаем, как избежать ошибки одновременного изменения при изменении ArrayList в Java.

Кстати, если вы не знакомы с коллекционными классами, например, с самим ArrayList, то вам следует присоединиться к онлайн-курсу, например
Основы Java: научитесь правильно писать код на Udemy – это хорошее место для начала.

ConcurrentModificationException в одной теме

Это первый пример воспроизведения исключения одновременной модификации в Java. В этой программе мы перебираем ArrayList, используя расширенный цикл foreach, и удаляем селективные элементы, например, элемент, который соответствует определенному условию, используя метод удаления ArrayList.

Например, в приведенном ниже коде мы сначала добавили пару хороших книг по программированию, например, « Программирование жемчужин» , « Чистый код» , « Код завершен», в ArrayList, а затем удалили любой элемент, в заголовке которого есть «Код».

Class ConcurrentModificationException

For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.

Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

How to Avoid the Concurrent Modification Exception in Java

How to Avoid the Concurrent Modification Exception in Java

The ConcurrentModificationException is a very common exception in Java that occurs usually while working with Collections. The ConcurrentModificationException is used to fail-fast when something being iterated on is modified.

This exception occurs when an object is attempted to be modified concurrently without permission. For example, if a Collection is modified while a thread is traversing it using an Iterator , a ConcurrentModificationException is thrown from the Iterator.next() method.

The ConcurrentModificationException can occur in both multithreaded and single-threaded environments.

What Causes ConcurrentModificationException

The ConcurrentModificationException generally occurs when working with Java Collections. The Collection classes in Java are very fail-fast and if they are attempted to be modified while a thread is iterating over it, a ConcurrentModificationException is thrown.

This exception can occur in both multithreaded and single-threaded Java environments. Here are examples of each:

  • Multithreaded environment — If a thread is traversing over a Collection using an Iterator and another thread attempts to add or remove elements to the Collection .
  • Single-threaded environment — When an element is attempted to be removed from an ArrayList using the remove() method while it is being traversed using an enhanced for loop.

ConcurrentModificationException Example

Here is an example of a ConcurrentModificationException thrown when attempting to remove an element from an ArrayList using the remove() method while traversing it using an enhanced for loop:

Since the enhanced for loop uses an Iterator internally to traverse elements in a Collection , running the above code causes a ConcurrentModificationException since the remove() method of the Collection is used instead of the iterator:

How to Resolve ConcurrentModificationException

The above exception can be resolved by traversing the elements of the ArrayList using a traditional for loop instead of the enhanced for loop. Since the traditional for loop does not use an Iterator to traverse the elements of a Collection , it does not cause a ConcurrentModificationException :

Since the ConcurrentModificationException belongs to the Iterator and not the remove() method of the ArrayList , running the above code will produce the correct output as expected:

The above exception can also be resolved by using an Iterator to traverse the elements of the ArrayList and using the Iterator.remove() method to remove elements. Alternatively, the Collection.removeIf() method introduced in Java 8 can be used to remove an element from a Collection if a given condition is true.

How to Avoid ConcurrentModificationException in Multithreaded Environments

To avoid the ConcurrentModificationException in multithreaded environments, certain precautions can be used:

  • Iterating over an array instead of a collection — this can work well with small-sized lists but can degrade performance for larger ones.
  • Locking the collection by placing it in a synchronized block — this may not be the most effective approach as it does not utilize the very purpose of multi-threading.
  • Using Java concurrent collections such as ConcurrentHashMap and CopyOnWriteArrayList classes can help avoid the ConcurrentModificationException.

Track, Analyze and Manage Errors with Rollbar

Rollbar in action

Fixing Errors in your Java code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring, tracking and triaging, making fixing Java errors easier than ever. Sign Up Today!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *