java.util.ConcurrentModificationException upon LinkedHashSet iteration - java

Please, help me understand the error I am getting:
private void replayHistory() {
synchronized (alarmsHistory) {
for (AlarmEvent alarmEvent : alarmsHistory) {
LOG.error("replayHistory " + alarmEvent.type + " " + alarmEvent.source);
sendNotification(alarmEvent.type, alarmEvent.source, alarmEvent.description,
alarmEvent.clearOnOtherStations, alarmEvent.forceClearOnOtherStations);
}
}
}
and the method that adds an element to it
private void addToAlarmsHistory(AlarmEvent alarmEvent) {
synchronized (alarmsHistory) {
LOG.error("addToAlarmsHistory " + alarmEvent.type + " " + alarmEvent.source);
alarmsHistory.add(alarmEvent);
}
}
both methods and the Set
private volatile Set<AlarmEvent> alarmsHistory = new LinkedHashSet<AlarmEvent>();
are defined in
JmxGwReloadThread extends Thread class
which is an inner class in
AlarmManager class
that has a method
private void addToReplayHistory(AlarmEvent alarmEvent) {
if ((jmxThread != null) && (jmxThread.isAlive())) {
jmxThread.addToAlarmsHistory(alarmEvent);
}
}
which is being called by different interfaces (cannot assure when and how often)
At some point JmxThread is started and calls replayHistory method
java.util.ConcurrentModificationException is thrown, the root is from the
for (AlarmEvent alarmEvent : alarmsHistory) {
The code propably tries to add an element to the alarmsHistory and when interator
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:390)
at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:401)
at AlarmManager$JmxGwReloadThread.replayHistory(AlarmManager.java:568)
at AlarmManager$JmxGwReloadThread.run(AlarmManager.java:532)
throws exception upon calling nextEntry, but should't synchronization prevent from such an issue?
Logs show that synchronization does not work - replayHistory should iterate over all its elements (I can asure its more then one single HEARTBEAT_INFO FM) but it's interrupted by the addToReplayHistory call.
2013-07-11 11:58:33,951 Thread-280 ERROR AlarmManager$JmxGwReloadThread.replayHistory(AlarmManager.java:570) - replayHistory HEARTBEAT_INFO FM
2013-07-11 11:58:33,951 Thread-280 ERROR AlarmManager$JmxGwReloadThread.addToAlarmsHistory(AlarmManager.java:550) - addToAlarmsHistory HEARTBEAT_INFO FM
2013-07-11 11:58:33,952 Thread-280 ERROR Log4jConfigurator$UncaughtExceptionHandler.uncaughtException(Log4jConfigurator.java:253) - Detected uncaught exception in thread: Thread-280

One thing OP (and probably most people) should be aware of:
ConcurrentModificationException has nothing to do with multi-threading.
Although multi-threading makes it much easier to happen, but the core of this problem has nothing to do with multi-threading.
This is mostly caused by scenario like,
Get the iterator from a collection,
Before finish using that iterator, the collection is structurally modified.
Keep on using the iterator after 2. The iterator will detect the collection is structurally modified and will throw out ConcurrentModificationException.
Of course, not all collection have such behavior, e.g. ConcurrentHashMap. Definition of "Structurally Modified" is different for different collection too.
That means, even I have only 1 thread, if I do something like:
List<String> strings = new ArrayList<String>();
//....
for (String s: strings) { // iterating through the collection
strings.add("x"); // structurally modifying the collection
}
I will get ConcurrentModificationException even it is all happening in single thread.
There are different ways to solve the problem, depending on your requirement or problem. e.g.
If it is simply due to multi-thread access, proper synchronize access can be one solution
You may make use of Collection that iterator is safe from structural modification (e.g. ConcurrentHashMap)
Adjust your logic to either re-acquire the iterator again if you modified the collection, or makes your modification using the iterator (some collection impls allows that), or make sure modification to collection happens after you finish using the iterator.
Given that your code seems having proper synchronization on alarmHistory, there are two directions you would want to check
Is there any possible modification of alarmHistory inside sendNotification()? For example, adding or removing from alarmHistory?
Is there other possible unsynchronized access to alarmHistory which may modify the structure?

If one thread iterates, and another thread adds, you're hosed.
Given that your code seems to synchronise access to the two relevant blocks of code, look for other unsynchronized code that adds/removes from alarmsHistory.

The only idea which comes to my head that you have an intricate logic behind the scene. I think the sendNotification somehow recursively invokes addToReplayHistory. So, the multithreading is a red herring, the log file shows only one thread involved, and immideately after sendNotification there is addToReplayHistory call which modifies the collection and breaks the interator.
More info is in the javadoc for the exception:
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.

To add some details to kan's answer:
The synchronized block in Java is reentrant:
Reentrant SynchronizationRecall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock. Without reentrant synchronization, synchronized code would have to take many additional precautions to avoid having a thread cause itself to block.
So like kan pointed out, it might in fact be that not multiple threads are modifying your collection but only one thread which, due to the reentrant behavior, may always acquire the lock.
The things you should look for to fix the exception are recursive calls between synchronized blocks, or unsychronized access to alarmsHistory.
You can also look into concurrent collections like ConcurrentSkipList or CopyOnWriteArraySet. Both should prevent the exception, but beware of their behavior and performance characteristics described in the JavaDoc.

Related

Why do we use synchronized collection if it doesn't guarantee the synchronized access on iterators?

For example, in the code below, we have to wrap list in a synchronized block when doing the iteration. Does the Collections.synchronizedList make the list synchronized? Why do we do this if it doesn't provide any convenience? Thanks!
List<Integer> list = Collections.synchronizedList( new ArrayList<>(Arrays.asList(4,3,52)));
synchronized(list) {
for(int data: list)
System.out.print(data+" ");
}
See https://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html
The reason is that iteration is accomplished via multiple calls into the collection, which must be composed into a single atomic operation.
Also see https://www.baeldung.com/java-synchronized-collections
Why do we do this if it doesn't provide any convenience
That it does not help you when iterating is not the same as providing no convenience.
All of the methods - get, size, set, isEmpty etc - are synchronized. This means that they have visibility of all writes made in any thread.
Without the synchronization, there is no guarantee that updates made in one thread are visible to any other threads, so one thread might see a size of 5 which another sees a size of 6, for example.
The mechanism for making the list synchronized is to make all of its methods synchronized: this effectively means that the body of the method is wrapped in a synchronized (this) { ... } block.
This is still true of the iterator() method: that too is synchronized. But the synchronized block finishes when iterator() returns, not when you finish iterating. It's a fundamental limitation of the way the language is designed.
So you have to help the language by adding the synchronized block yourself.
Wrapper is used to synchronize addition and removal elements from wrapped collection.
JavaDoc mentions that iteration is not synchronized an you need to synchronize it yourself.
* It is imperative that the user manually synchronize on the returned
* list when iterating over it
But other access operations are thread-safe and also establish happens before relation (since they use synchronized).
Collections.synchronizedList method synchronises methods like add, remove. However, it does not synzhronize iterator() method. Consider the following scenario:
Thread 1 is iterating through the list
Thread 2 is adding an element into it
In this case, you will get ConcurrentModificationException and hence, it's imperative to synzhronize the calls to iterator() method.

Java - ConcurrentModificationException in multithreaded program, Set is wrapped with synchronized

I have a crash in the following code:
private LocalBundle(Bundle b, Map<Bundle, LocalBundle> clonnedObjs) {
this();
synchronized (b.getVariables()) { // b.getVariables() is Set
addFrom(b, clonnedObjs);
}
}
but in addFrom I get the crash:
private synchronized void addFrom(Bundle b, Map<Bundle, LocalBundle> clonnedObjs) {
Set<TaintedVariable> variablesOfBundle = b.getVariables();
for(TaintedVariable v : variablesOfBundle) {
Exception message:
Exception in thread "pool-4-thread-1" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at x.y.z.LocalBundle.addFrom(VisitedNodesWithBundle.java:198)
Does someone know why it happens? I wrapped with synchronized (b.getVariables()), but it looks like that two threads are executing for(TaintedVariable v : variablesOfBundle)
The thing to remember about synchronized is that it only guarantees exclusive access if everybody accessing the shared resource also synchronizes.
For example, you can synchronize access to a shared variable:
synchronized (foo) {
foo.setBar();
}
And you can think that you have exclusive access to it. However, there is nothing to stop another thread just doing something without the synchronized block:
foo.setBar(); // No synchronization first.
From your description, it sounds like this is happening; you've not given any details of what the "rogue" thread is doing, though.
If it is simply adding elements to the set, you can make your set synchronized when you create it:
Collections.synchronizedSet(new HashSet<TaintedVariable>());
Now individual calls to methods on the set will be synchronized, and so you would no longer get a CME. Note, however, that the synchronization is applied per method call: if you make a sequence of calls (e.g. if set contains foo then add bar), you need an explicit synchronized block around that logic.
I'm not sure, that the reason is another thread. Take a closer look at javadoc for this exception. It's said that:
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.
That means, that you may cause such exception in a single thread if you try to modify the collection while you are iterating over it.
You have to check out, whether your code tries to modify the variablesOfBundle collection in this for-loop
for(TaintedVariable v : variablesOfBundle)

Hashtable: why is get method synchronized?

I known a Hashtable is synchronized, but why its get() method is synchronized?
Is it only a read method?
If the read was not synchronized, then the Hashtable could be modified during the execution of read. New elements could be added, the underlying array could become too small and could be replaced by a bigger one, etc. Without sequential execution, it is difficult to deal with these situations.
However, even if get would not crash when the Hashtable is modified by another thread, there is another important aspect of the synchronized keyword, namely cache synchronization. Let's use a simplified example:
class Flag {
bool value;
bool get() { return value; } // WARNING: not synchronized
synchronized void set(bool value) { this->value = value; }
}
set is synchronized, but get isn't. What happens if two threads A and B simultaneously read and write to this class?
1. A calls read
2. B calls set
3. A calls read
Is it guaranteed at step 3 that A sees the modification of thread B?
No, it isn't, as A could be running on a different core, which uses a separate cache where the old value is still present. Thus, we have to force B to communicate the memory to other core, and force A to fetch the new data.
How can we enforce it? Everytime, a thread enters and leaves a synchronized block, an implicit memory barrier is executed. A memory barrier forces the cache to be updated. However, it is required that both the writer and the reader have to execute the memory barrier. Otherwise, the information is not properly communicated.
In our example, thread B already uses the synchronized method set, so its data modification is communicated at the end of the method. However, A does not see the modified data. The solution is to make get synchronized, so it is forced to get the updated data.
Have a look in Hashtable source code and you can think of lots of race conditions that can cause problem in a unsynchronized get() .
(I am reading JDK6 source code)
For example, a rehash() will create a empty array, and assign it to the instance var table, and put the entries from old table to the new one. Therefore if your get occurs after the empty array assignment, but before actually putting entries in it, you cannot find your key even it is in the table.
Another example is, there is a loop iterate thru the linked list at the table index, if in middle in your iteration, rehash happens. You may also failed to find the entry even it exists in the hashtable.
Hashtable is synchronized meaning the whole class is thread-safe
Inside the Hashtable, not only get() method is synchronized but also many other methods are. And particularly put() method is synchronized like Tom said.
A read method must be synchronized as a write method because it will make sure the visibility and the consistency of the variable.

Manually need to synchronize access to synchronized list/map/set etc

Collection class provides various methods to get thread safe collections . Then why is it necessary to manually synchronize access while iterating ?
Each method is thread safe. If you make multiple calls to a synchronized collection this is not thread safe unless you hold a lock explicitly. Using an Iterator involves making multiple calls to the iterator implicitly so there is no way around this.
What some of the Concurrency Libraries collections do is provide weak consistency. They provide a pragmatic solution which is that an added or removed element may, or may not be seen when Iterating.
A simple example of a thread safe collection used in an unsafe manner.
private final List<String> list = Collections.synchronizedList(
new ArrayList<String>());
list.add("hello");
String hi = list.remove(list.size()-1);
Both add and remove are thread safe and you won't get an error using them individually. The problem is another thread can alter the collection BETWEEN calls (not within calls) causing this code to break in a number of ways.

synchronizedCollection and contains--do I need to synchronize manually?

I'm using Collections.synchronizedCollection in Java to protect a Set that I know is getting accessed concurrently by many threads. The Java API warns:
" It is imperative that the user manually synchronize on the returned collection when iterating over it:
Collection c = Collections.synchronizedCollection(myCollection);
...
synchronized(c) {
Iterator i = c.iterator(); // Must be in the synchronized block
while (i.hasNext())
foo(i.next());
}
"
If I use c.contains(obj), is that thread-safe? Internally, obviously, this is iterating over the Collection and seeing if any of the objects in it are equal to obj. My instinct is to assume that this is probably synchronized (it would seem to be a major failing if not), but given previous pains with synchronization, it seems wise to double-check, and a Google search for answers on this hasn't turned up anything.
In itself, a call to contains is safe.
The problem is that one often tests whether a collection contains an element then does something to the collection based on the result.
Most likely, the test and the action should be treated as a single, atomic operation. In that case, a lock on the collection should be obtained, and both operations should be performed in the synchronized block.
Collections.synchronizedCollection() will return a thread safe collection which means
any single method call is thread safe by itself. It depends what you want do. If you want to call couple of methods, java cannot make it thread safe together.
It's safe, because contains itself is synchronized.

Categories

Resources