Class ConcurrentModificationException
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
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.
Minecraft Forums
Error: Encountered an unexpected exception java.util.ConcurrentModificationException: null
Hello! We have been playing this Aternos server for a while and while building our base, the server just closes every 5 minutes and I think it’s because of adding an item to the base that is maybe corrupted to something? But here is the log from the server. -> https://mclo.gs/Hx5x2Fv
- Farlander
- Join Date: 9/20/2016
- Posts: 18,563
- Location: Germany
- Member Details
space
- Farlander
- Join Date: 9/20/2016
- Posts: 18,563
- Location: Germany
- Member Details
Maybe an issue with invalid entities — does it work with a new map?
space
Should we like try generate a new world?
- Farlander
- Join Date: 9/20/2016
- Posts: 18,563
- Location: Germany
- Member Details
space
- Enderdragon Slayer
- Join Date: 10/6/2013
- Posts: 13,022
- Minecraft: TheMasterCaver
- Member Details
It is hard to say what is causing the error but it means that a hashmap is being modified while it is being iterated over, often involving multiple threads, and all the similar reports I’ve seen suggest removing mods one at a time until it is fixed (for example); since the crash report only includes the stacktrace for the current thread there is no way to know which mod is the culprit unless it happens to crash in the other thread or you can get a heap dump (the only option I’ve seen though is for an out of memory error, and you’d need special tools to analyze the file). However, the world itself is unlikely to be corrupted (though crashes can corrupt it). You could also try searching for the error and the mods you have to see if any are directly associated with it as certain mods have been known to cause it (for example, BuildCraft has had this issue (you don’t have this but this is one of various mods that came up), note also that specific mod versions may be buggy, which is why it is a good idea to make sure you are running the latest versions).
TheMasterCaver’s First World — possibly the most caved-out world in Minecraft history — includes world download.
TheMasterCaver’s World — my own version of Minecraft largely based on my views of how the game should have evolved since 1.6.4.
Why do I still play in 1.6.4?
Избавляемся от ConcurrentModificationException
Как известно, ConcurrentModificationException к многопоточности никакого отношения не имеет. Возникает эта гадость, когда мы пытаемся модифицировать коллекцию во время итерирования по ней. Как обычно, это имеет исторические корни: коллекции и итераторы появились в Java 1.2, в те времена избежать явного использования итератора при обходе коллекции было никак нельзя, так что предложение менять коллекцию посредством методов итератора не выглядело совсем ужасным:
Iterator iterator = collection.iterator(); while (iterator.hasNext()) < Object element = iterator.next(); if (iDontLikeThisElement(element)) < iterator.remove(); >>
Не, всё же выглядело. Но никаких других вариантов не было. Позже в пятой джаве появляется цикл foreach, и использование итераторов становится преимущественно неявным:
for (E element : collection) < if (iDonLikeThisElement(element)) < collection.remove(element); // облом! ConcurrentModificationException! >>
«Ишь чего захотели! Юзайте явные итераторы, дорогие кастомеры, и не выделывайтесь» — наверное что-то такое думали разработчики джава платформы работая над пятеркой.
В шестой джаве появляется пакет конкаренси. Теперь можно cделать так:
Set set = Collections.newSetFromMap(new ConcurrentHashMap<>());
И получить set который не кидается ConcurrentModificationException-ами. Но опять же счастье не совсем полное:
- Oбычно многопоточность нам вовсе не нужна
- Не подерживаются null ни в качестве элементов, ни ключей, ни значений. Да и ладно, честно сказать.
- Порядок элементов не определён и может меняться — вот это гораздо хуже. Т.е. если мы бежим по элементам и ведём некий подсчёт с потерей точности, то нас могут поджидать неприятные сюрпризы и разные результаты на одних и тех же наборах данных, что, скажем, не всегда хорошо. Так же бывают задачи, где желательно сохранить именно изначальный порядок данных. Ну и вот такие штуки тоже имеют место быть:
set.add("aaa"); set.add("bbb"); for (String s : set)
set.add("aaa"); set.add("bbb"); for (String s : set)
- В рамках одного треда можно добавлять и удалять элементы в любой момент без всяких эксепшенов. И конечно же за константное время.
- Можно хранить null-ы, если вдруг хочется.
- Элементы обходятся в том порядке в котором были добавлены.
- Удаляя элемент мы не будем обнулять ссылку на следующий, т. е. eсли итератор стоит на данном элементе, то он сможет пройти дальше.
- В конце списка поместим фэйковый элемент, который превращается в настоящий когда в список что-нибудь добавляют. Т.е. даже добравшись до конца списка итератор не упирается в null и может продолжить работу если в коллекции появляется новый элемент. Далее в коде этот фейковый элемент называется placeholder.
- В начале у нас есть элементы A, B, C, D.
- Затем элементы C и D удаляются.
- Добавляется новый элемент E.
Ну и для константного времени доступа нам, очевидно, нужен хэшмап:
import java.util.AbstractSet; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; public class LinkedSet extends AbstractSet < private static class LinkedElement < E value; boolean exists; LinkedElementprev; LinkedElement next; > private Map map = new HashMap<>(); private LinkedElement placeholder = new LinkedElement<>(); private LinkedElement head = placeholder; @Override public boolean isEmpty() < return head == placeholder; >@Override public int size() < return map.size(); >@Override public boolean contains(Object o) < return map.containsKey(o); >// здесь будут методы для добавления, удаления, итерирования >
@Override public boolean add(E e) < LinkedElementelement = map.putIfAbsent(e, placeholder); if (element != null) < return false; >element = placeholder; element.exists = true; element.value = e; placeholder = new LinkedElement<>(); placeholder.prev = element; element.next = placeholder; return true; >
@Override public boolean remove(Object o) < LinkedElementremovedElement = map.remove(o); if (removedElement == null) < return false; >removeElementFromLinkedList(removedElement); return true; > private void removeElementFromLinkedList(LinkedElement element) < element.exists = false; element.value = null; element.next.prev = element.prev; if (element.prev != null) < element.prev.next = element.next; element.prev = null; >else < head = element.next; >>
@Override public Iterator iterator() < return new ElementIterator(); >private class ElementIterator implements Iterator < LinkedElementnext = head; LinkedElement current = null; LinkedElement findNext() < LinkedElementn = next; while (!n.exists && n.next != null) < next = n = n.next; >return n; > @Override public boolean hasNext() < return findNext().exists; >@Override public E next() < LinkedElementn = findNext(); if (!n.exists) < throw new NoSuchElementException(); >current = n; next = n.next; return n.value; > @Override public void remove() < if (current == null) < throw new IllegalStateException(); >if (map.remove(current.value, current)) < removeElementFromLinkedList(current); >else < throw new NoSuchElementException(); >> >
Set set = new LinkedSet<>(); // . put some numbers set.stream().filter(v -> v % 2 == 0).forEach(set::remove);
Понятно, что аналогично можно сконструировать и LinkedMap. Вот в общем-то и всё, ещё один велосипед готов. Почему подобным образом не доработали библиотечные LinkedHashMap и LinkedHashSet? Кто знает, возможно чтобы джависты завидовали джаваскриптистам.