Concurrentmodificationexception Despite Using Synchronized

ConcurrentModificationException despite using synchronized

ConcurrentModificationException usually has nothing to do with multiple threads. Most of the time it occurs because you are modifying the collection over which it is iterating within the body of the iteration loop. For example, this will cause it:

Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
Item item = (Item) iterator.next();
if (item.satisfiesCondition()) {
collection.remove(item);
}
}

In this case you must use the iterator.remove() method instead. This occurs equally if you are adding to the collection, in which case there is no general solution. However, the subtype ListIterator can be used if dealing with a list and this has an add() method.

ConcurrentModificationException on synchronized method

You've shows us how map Tabs is created (Java naming conventions would dictate its name begin with a lowercase letter), but not how it is populated. As it is, the map would always be empty, and the while loop would run zero times. Also, the local variable tabname is unused, but presumably is not unused in your actual code.

That said, it appears that ProcessEvent will be run once for every event. It is static, and synchronized, which means that it will obtain the monitor for MainActivity.class, and no other method that synchronizes on the same object can run at the same time.

However, it starts a new thread, which does the actual work, and returns immediately. That thread is not synchronized, and so any number of these worker threads can be running at the same time, all using the same map. The map is wrapped with Collections.synchronizedMap and that is the only protection against concurrent modifications.

Such a synchronized map will not allow multiple callers to call its methods at the same time, but separate calls to different methods can be interleaved arbitrarily. For instance, while one caller is putting a new entry into the map, no other caller can access the map. However, it is possible for one caller to get the key set from the map, get the iterator from the key set, and start iterating over it, and then for another caller in another thread to add, modify, or remove an entry, and, finally, for the first thread to continue iterating over the key set and get a ConcurrentModificationException.

I would suggest using java.util.concurrent.ConcurrentHashMap instead, and removing the synchronized keyword from ProcessEvent.

Already synchronized, but got ConcurrentModificationException

Synchronizing doesn't do anything to prevent the ConcurrentModificationException if the synchronized code modifies the collection during iteration, which you do here:

for (GatewayMsg msg : PacketQueue){
PacketQueue.remove(msg); // <== Not allowed during iteration
packetHandler.onPacket(msg);
}

During an iteration, you may only remove elements via an Iterator, e.g.:

Iterator<GatewayMsg> it = PacketQueue.iterator();
while (it.hasNext()) {
GatewayMsg msg = it.next();
it.remove(); // <== This is allowed, provided the collection supports it
packetHandler.onPacket(msg);
}

Why is there a ConcurrentModificationException even when list is synchronized?

The basic problem is that a synchronized list is not synchronized in a useful way.

The problem is that while its methods are synchronized, actions like moving elements that should be atomic are not, because the separate calls needed for the move are not synchronized together. It means other threads can get in between individual method calls. Thus synchronized collections are largely deprecated now.

Despite this flaw, if you have another thread add an element while your thread is sorting, you'll get this exception because sort iterates and changing the list during iteration causes the exception.

Fortunately, the JDK has new Collection classes that have industrial strength (and useful) synchronization, courtesy of the java.util.concurrent package.

Replace your list with a CopyOnWriteArrayList, don't "synchronize" it and you'll be good to go.

Synchronize methods to prevent ConcurrentModificationException

Because locks are re-entrant, synchronizing access to the collection won't stop the same thread iterating over a collection, and then modifying the collection itself. Despite the name, ConcurrentModificationException is not always raised due to concurrent modification by another thread. Registering or un-registering other observers in a notification callback is a prime culprit for such concurrent modification.

A common strategy for firing events is to take a "snapshot" of the listeners to be notified before delivering any events. Because the order in which observers are notified is generally unspecified, it's valid for all observers that were registered when an event is generated to receive it, even if another observer de-registers it as a result of that notification.

To make a snapshot, you can copy the observers to a temporary collection or array:

Collection<?> observers = new ArrayList<>(mySet);

or

Object[] observers = mySet.toArray(new Object[mySet.size()]);

Then iterate over that copy, leaving the original available for update:

for (Object o : observers) {
...
doSomething(o, ...);
...
}

Some concurrent collections like ConcurrentSkipListSet won't raise an exception, but they only guarantee "weakly consistent" iteration. This could result in some (newly added) observers unexpectedly receiving the current notification. CopyOnWriteArraySet uses a snapshotting technique internally. If you rarely modify the set, it will be more efficient, because it only copies the array when necessary.

Vector throws ConcurrentModificationException despite being synchronized

From the docs:

if the vector is structurally modified at any time after the iterator
is created, in any way except through the iterator's own remove or add
methods, the iterator will throw a ConcurrentModificationException.

The following code creates an iterator under the covers:

for (int num : numbers) {
sum += num;
}

So when one threads modifies the vector (by adding elements) while another vector is iterating it - you'll see a ConcurrentModificationException

There are different options to solve it, one way could be to read from a file into another vector and when the reading is done assign this other vector to numbers (since assignment is an atomic operation). Keep in mind that in order for the change to be visible to other threads you'll need to declare numbers as volatile.

ConcurrentModificationException on synchronized() code - how is it possible?

Agree with your diagnosis so far. There is a second way to get a ConcurrentModificationException that is commonly overlooked...

Those synchronized locks are re-entrant which means the thread holding the lock in one method can access all methods. So the thread causing your CME is quite possibly a callback from within the for loop that ends up back in your connection-listener methods.

IMO, the most likely scenario is that the connection is only detected as closed when trying to sendMessage.

Resolution: There are cleverer solutions but this is one that cannot go wrong:

  // Take copy of sockets before iterating it to defend against self-induced ConcurrentModificationException
for (WebSocketSession session : new HashSet<>(this.sockets)) {

Getting ConcurrentModificationException despite using synchronized to sort a Collection

Rob Spoor explained why ConcurrentModificationException isn't necessarily about threading. But also, you should know this:

The synchronized keyword on the run() method in your example has no effect.

When you write a synchronized method,

    public synchronized void bar() {
...
}

That's the same as if you wrote,

    public void bar() {
synchronized(this) {
...
}
}

In your example, each of the three tasks that you submit to the executor service is a different Runnable object. The keyword, this, refers to a different object in each of the three run() methods. Three different threads synchronizing on three different objects is the same as no synchronization at all.

Synchronization is only meaningful when the threads synchronize on the same object. The rule is, no two threads will ever be allowed to synchronize on the same object at the same time.

Java HashMap ConcurrentModification Exception despite using synchronized block

It will only be thread-safe if every access (both reads and writes) to the map is performed via a synchronized block.

ConcurrentModificationException will be thrown when the map is being iterated on while it is being modified.

I would suggest you switch to a ConcurrentHashMap which is thread-safe and will be a drop-in replacement.



Related Topics



Leave a reply



Submit