Concurrent Modification Exceptions - java

I am getting the following java.util.ConcurrentModificationException on this method
private AtomicReference<HashMap<String, Logger>> transactionLoggerMap = new AtomicReference<HashMap<String,Logger>>();
public void rolloutFile() {
// Get all the loggers and fire a temp log line.
Set<String> transactionLoggerSet = (Set<String>) transactionLoggerMap.get().keySet();
Iterator<String> transactionLoggerSetIter = transactionLoggerSet.iterator();
while(transactionLoggerSetIter.hasNext()){
String key = (String) transactionLoggerSetIter.next();
Logger txnLogger = transactionLoggerMap.get().get(key);
localLogger.trace("About to do timer task rollover:");
txnLogger.info(DataTransformerConstants.IGNORE_MESSAGE);
}
}
Please suggest, if I am using a Atomic Reference, how do i get a como?

A ConcurrentModificationException means that you have modified the collection outside of the iterator. I don't see any modifications in your loop so I assume that there is another thread that is also adding or removing from the transactionLoggerMap at the same time you are iterating across it.
Even though you have it wrapped in an AtomicReference, you still cannot have two threads making changes to the same unsynchronized collection at the same time. AtomicReference does not synchronize the object it is wrapping -- it just gives you a way to atomically get and set that reference.
You will need to make this a synchronized collection either by using the ConcurrentHashMap class or wrapping your HashMap using the Collections.synchronizedMap(map) method.

Because you are not protecting against concurrent modifications during your iteration. The Atomic reference only makes sure you get your Map (and it's contents).

Maybe you can consider iterating over a local copy of the collection instead of the same collection. It would be an easy way to ensure your collection will not be modified while you're looping over it. It is advisable to use immutable objects on a multi-threaded environment and you prevent this kind of problems for free.
Hope it helps.

Remove the redundant
Set<String> transactionLoggerSet = (Set<String>) transactionLoggerMap.get().keySet();
You would still have to use synchronization as you are iterating over the map. SynchronizedMap guarentees consistency for its API methods. For the rest, you would need to do client side synchronization

Related

Are final unmodifiable sets thread safe?

The javadocs are not clear about this: are unmodifiable sets thread safe? Or should I worry about internal state concurrency problems?
Set<String> originalSet = new HashSet<>();
originalSet.add("Will");
originalSet.add("this");
originalSet.add("be");
originalSet.add("thread");
originalSet.add("safe?");
final Set<String> unmodifiableSet = Collections.unmodifiableSet(originalSet);
originalSet = null; // no other references to the originalSet
// Can unmodifiableSet be shared among several threads?
I have stumbled upon a piece of code with a static, read-only Set being shared against multiple threads... The original author wrote something like this:
mySet = Collections.synchronizedSet(Collections.unmodifiableSet(originalSet));
And then every thread access it with code such as:
synchronized (mySet) {
// Iterate and read operations
}
By this logic only one thread can operate on the Set at once...
So my question is, for a unmodifiable set, when using operations such as for each, contains, size, etc, do I really need to synchronize access?
If it's an unmodifiable Set<String>, as per your example, then you're fine; because String objects are immutable. But if it's a set of something that's not immutable, you have to be careful about two threads both trying to change the same object inside the set.
You also have to be careful about whether there's a reference somewhere to the Set, that's not unmodifiable. It's possible for a variable to be unmodifiable, but still be referring to a Set which can be modified via a different variable; but your example seems to have that covered.
Objects that are "de facto" immutable are thread safe. i.e. objects that never change their state. That includes objects that could theoretically change but never do.
However all the objects contained inside must also be "de facto" immutable.
Furthermore the object only starts to become thread safe when you stop modifying it.
And it needs to be passed to the other threads in a safe manner. There are 2 ways to do that.
1.) you start the other threads only after you stopped modifying your object. In that case you don't need any synchronization at all.
2.) the other threads are already running while you are modifying the object, but once you completed constructing the object, you pass it to them through a synchronized mechanism e.g. a ConcurrentLinkedDeque. After that you don't need any further synchronization.

concurrent HashMap: checking size

Concurrent Hashmap could solve synchronization issue which is seen in hashmap. So adding and removing would be fast if we are using synchronize key work with hashmap. What about checking hashmap size, if mulitple threads checking concurrentHashMap size? do we still need synchronzation key word: something as follows:
public static synchronized getSize(){
return aConcurrentHashmap.size();
}
concurentHashMap.size() will return the size known at the moment of the call, but it might be a stale value when you use that number because another thread has added / removed items in the meantime.
However the whole purpose of ConcurrentMaps is that you don't need to synchronize it as it is a thread safe collection.
You can simply call aConcurrentHashmap.size(). However, you have to bear in mind that by the time you get the answer it might already be obsolete. This would happen if another thread where to concurrently modify the map.
You don't need to use synchronized with ConcurretnHashMap except in very rare occasions where you need to perform multiple operations atomically.
To just get the size, you can call it without synchronization.
To clarify when I would use synchronization with ConcurrentHashMap...
Say you have an expensive object you want to create on demand. You want concurrent reads, but also want to ensure that values are only created once.
public ExpensiveObject get(String key) {
return map.get(key); // can work concurrently.
}
public void put(String key, ExepensiveBuilder builder) {
// cannot use putIfAbsent because it needs the object before checking.
synchronized(map) {
if (!map.containsKey(key))
map.put(key, builder.create());
}
}
Note: This requires that all writes are synchronized, but reads can still be concurrent.
The designers of ConcurrentHashMap thought of giving weightage to individual operations like : get(), put() and remove() over methods which operate over complete HashMap like isEmpty() or size(). This is done because the changes of these methods getting called (in general) are less than the other individual methods.
A synchronization for size() is not needed here. We can get the size by calling concurentHashMap.size() method. This method may return stale values as other thread might modify the map in the meanwhile. But, this is explicitely assumed to be broken as these operations are deprioritized.
ConcorrentHashMap is fail-safe. it won't give any concurrent modification exceptions. it works good for multi threaded operations.
The whole implementation of ConcurrentHashMap is same as HashMap but the while retrieving the elements , HashMap locks whole map restricting doing further modifications which gives concurrent modification exception.'
But in ConcurrentHashMap, the locking happens at bucket level so the chance of giving concurrent modification exception is not present.
So to answer you question here, checking size of ConcurrentHashMap doesn't help because , it keeps chaining based on the operations or modification code that you write on the map. It has size method which is same from the HashMap.

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.

How to prevent nested synchronized blocks when iterating over a collection

In a multithreaded Java application I need to iterate over a collection of objects. Since both the collection and the objects could be modified by another thread while I iterate over them, I need to use synchronization.
However nested synchronized blocks are not recommended since they could lead to deadlocks. How would I solve this problem?
Collection<Data> dataCollection = something.getDataCollection();
synchronized ( dataCollection ) {
for ( final Data data : dataCollection ) {
synchronized ( data ) {
data.doSomething(); // doSomething() changes object state
}
}
}
I think you can use CopyOnWriteArrayList instead of the outer synchronization.
A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.
This is ordinarily too costly, but may be more efficient than alternatives when traversal operations vastly outnumber mutations, and is useful when you cannot or don't want to synchronize traversals, yet need to preclude interference among concurrent threads
You can take a copy of the collection and only lock one object at a time.
Collection<Data> dataCollection = something.getDataCollection();
Collection<Data> copy;
synchronized ( dataCollection ) {
copy = new ArrayList<Data>(dataCollection);
}
for (Data data : copy) {
synchronized ( data ) {
data.doSomething(); // doSomething() changes object state
}
}
Can't believe nobody pointed out that the number one way to avoid synchronizing on the Data object is to have this object itself thread-safe! It's also the correct way of handling synchronization - if you know that your object will be accessed by multiple threads, handle synchronization the way you see fit inside the class, not in the code that may access it. You will also certainly be more efficient because you can limit synchronization to just the critical blocks, use ReadWriteLock, j.u.c.atomic, etc
Nested synchronization can lead to deadlock, but it doesn't have to. One way to avoid deadlocks is to define an order that you synchronize objects and always follow it.
If you always synchronize the dataCollection object before you synchronize the data objects, you won't deadlock.
Take a look at ReentrantReadWriteLock. With this class you can implement a lock that makes it possible for any number of non-modifying (reading) threads to access the shared property simultaneously, but only one modifying (writing) thread to access it at a time (all other readers and writers are blocked until the writing thread releases the write-lock). Remember to test your implementation thorougly, as wrong usage of the locks can still lead to race condition and/or deadlocks.
Whether you use CopyOnWriteArrayList as Bozho said or copy the list before iterating as Peter says should depend on how much you expect the list to be edited compared to iterated over.
Use CopyOnWriteArrayList when you expect the list to be iterated over far more than it is modified.
Use copying the list if you think it will be modified far more than it is iterated over.
These should be the first options because concurrency solutions should be simple unless unavoidable, but if neither situation applies you will need to pick one of the more complicated strategies outlined in the comments here.
Good luck!

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