ConcurrentModifcationException when adding value to hashmap - java

The below code is receiving concurrent modificationexception when 2 thread access the same.
I would like to know whether
Whether this exception can be avoided if we use concurrent Hashmap.
If we use concurrent hashmap will there be any issue in a multithreaded environment.
or is there any other way to prevent this exception?
I donot intend use synchronzed as this code is used during polling. as one thread may have to wait for another to finish exceution.
The code is
HashMap<Integer, myModel> aServiceHash = new HashMap<Integer, myModel>();
HashMap<Integer, myModel> rServiceHash = new HashMap<Integer, myModel>();
for (myModel ser : serAccepted){
aServiceHash.put(service.getOriginalDate(), ser);
}
for (myModel ser : serRequested) {
if (aServiceHash.containsKey(service.getDate())) {
aServiceHash.put(serv.getDate(), serv);
}
else
rServiceHash.put(service.getDate(), ser);
}
Referred http://examples.javacodegeeks.com/java-basics/exceptions/java-util-concurrentmodificationexception-how-to-handle-concurrent-modification-exception/
http://www.journaldev.com/378/how-to-avoid-concurrentmodificationexception-when-using-an-iterator
How to avoid HashMap "ConcurrentModificationException" while manipulating `values()` and `put()` in concurrent threads?
Using JSF 2.1,JDK 7.1.

HashMap is not thread safe. ConcurrentHashMapis thread safe. When accessing a map from different threads, prefer it to be concurrent for thread safety.
And yes, it will avoid the exception.There will be no multithreading issues from that direction. You'll still need to make sure no thread removes something you intend to use later.
Another way to prevent the exception is to lock the map before each insert, whether through synchronized block or a Lock object.

Depending on your usage patterns and performance requirements, you could also build a copy-on-write map using a volatile HashMap delegate. This will give you one volatile read for each access whereas in ConcurrentHashMap you have a lot more, and they are a bit more expensive than ordinary reads or writes. Of course, copy-on-write schemes have their own drawbacks when you write to the map. But if you create the map from a pre-populated initial map and treat it as read-only afterwards, copy-on-write will be more efficient.

Related

Concurrency level for ConcurrentHashMap in synchronized method

I'm trying to fix a memory leak issue. Heap dump analysis shows that a ConcurrentHashMap is occupying around 98% of heap memory. Checked the code and it turns out that ConcurrentHashMap instantiation is using a constructor with no parameter. The default configuration for concurrencyLevel is 16. After this map instantiation I see a synchronized method call where data is being put in the map.
I would like to know that since data is being put only in synchronized method, is it safe to set concurrencyLevel of ConcurrentHashMap to 1?
Following is the sample code snippet:
private volatile Map<String, Integer> storeCache;
public void someMethod() {
storeCache = new ConcurrentHashMap<String, Integer>();
syncMethod();
}
private synchronized void syncMethod() {
storeCache.put("Test", 1);
}
I would like to know that since data is being put only in synchronized method, is it safe to set concurrencyLevel of ConcurrentHashMap to 1?
It's certainly safe, in the sense that it's not going to cause any Map corruption. However, it's not going to fix your memory leak. In fact, you probably don't want to synchronize access to the ConcurrentHashMap, which already guarantees safe reads and writes from multiple threads. Synchronizing externally is going to single-thread access to your CHM, which is going to eliminate many of the benefits of the CHM over a HashMap. If you remove the synchronized and specify a concurrencyLevel equal to the estimated number of concurrent writes, you'll probably achieve much better performance.
As for your memory leak, the keys and values in the CHM are strong references, meaning the Java garbage collector won't collect them, even if they're no longer referenced anywhere else in your code. So if you're using the CHM as a cache for temporary values, you'll need to .remove() them when your application no longer needs them.
(If you want the semantics of a ConcurrentMap without the strong keys, you can't get that out-of-the-box, but Guava provides a pretty good alternative.)
You may also want to check that the keys that you're .put()ing into the map have properly implemented .equals() and .hashCode().

Is setting a HashMap thread safe?

I have a HashMap in my program which is accessed by multiple threads, and is occasionally set by a single thread.
For example:
Map<String, String> myMap = new HashMap<String, String>();
This is accessed by multiple threads. Once an hour, a single thread calls:
myMap = myRefreshedVersionOfTheMap;
So my question is whether or not this is thread safe. If both maps always have the key "importantKey", is it possible for a reading thread to ever access the map at a time when "importantKey" does not exist?
Edit:
Thanks to the answers, I've realized this question is actually independent of the HashMap. It was more a question about object reference assignment.
This is not thread safe. Even though there are no writes to the map itself after the point of publication (from the point of view of the thread doing the publication), and reference assignment is atomic, the new Map<> has not been safely published. It particular, there are writes to the Map during its construction - either in the constructor, or after, depending on how you add those elements, and those writes may or may not be seen by other threads, since even though they intuitively occur before the map is published to the other threads, this isn't formally the case according to the memory model.
For an object to be safely published, it must be communicated to the outside world using some mechanism that either establishes a happens-before relationship between the object construction, the reference publication and the reference read, or it must use a handful of narrower methods which are guaranteed to be safe for publishing:
Initializing an object reference from a static initializer.
Storing a reference to it into a final field.
Your idiom would be safe if you declared myMap volatile. More details on safe publication can be found in JCIP (highly recommended), or here, or in this longer answer on a similar topic.
If you mean you are creating an entirely new Map and are assigning it to myMap which is what the other threads are accessing, then yes. Reference assignment is atomic. It's threadsafe because you are not modifying the contents of a Map while other threads are reading from it - you just have multiple threads reading from a Map.
You just need to declare it volatile so other threads don't cache it.
First off, Java's HashMap class is not thread safe, so there are no guarantees when reads and writes are happening concurrently.
However, since reads and writes to references in Java are atomic, then the pattern you described could be thread-safe as long as the refresh code is not mutating the old map. For example, the following would be fine:
// this refresh code would be thread-safe
Map<String, String> copy = new HashMap<String, String>(myMap);
copy.put(x, y); // change the map
myMap = copy;
// you might also consider
myMap = Collections.unmodifiableMap(copy);
// to make sure that the non-thread-safe map will never be mutated
One thing to consider with this pattern is that you may want the myMap field to be declared as volatile so that all threads will get the most recent version of myMap whenever they read from that variable.
Finally, as other posters have mentioned ConcurrentHashMap may be a better approach depending on the complexity of the refresh code. One disadvantage of ConcurrentHashMap is that it doesn't offer any way to batch the operations, so you'd have to make sure that the state at every point during the refresh process was valid for the rest of your application to consume.
HashMap is not thread safe. You can use any of the followings
ConcurrentHashMap.
HashMap with synchronized on the outside.
Different HashMap for each thread.
Check this similar answer here

Is this code multi-thread safe?

private static Map<Integer, String> map = null;
public static String getString(int parameter){
if(map == null){
map = new HashMap<Integer, String>();
//map gets filled here...
}
return map.get(parameter);
}
Is that code unsafe as multithreading goes?
As mentioned, it's definitely not safe. If the contents of the map are not based on the parameter in getString(), then you would be better served by initializing the map as a static initializer as follows:
private static final Map<Integer, String> MAP = new HashMap<Integer,String>();
static {
// Populate map here
}
The above code gets called once, when the class is loaded. It's completely thread safe (although future modification to the map are not).
Are you trying to lazy load it for performance reasons? If so, this is much safer:
private static Map<Integer, String> map = null;
public synchronized static String getString(int parameter){
if(map == null){
map = new HashMap<Integer, String>();
//map gets filled here...
}
return map.get(parameter);
}
Using the synchronized keyword will make sure that only a single thread can execute the method at any one time, and that changes to the map reference are always propagated.
If you're asking this question, I recommend reading "Java Concurrency in Practice".
Race condition? Possibly.
If map is null, and two threads check if (map == null) at the same time, each would allocate a separate map. This may or may not be a problem, depending mainly on whether map is invariant. Even if the map is invariant, the cost of populating the map may also become an issue.
Memory leak? No.
The garbage collector will do its job correctly regardless of the race condition.
You do run the risk of initializing map twice in a multi-threaded scenario.
In a managed language, the garbage collector will eventually dispose of the no-longer-referenced instance. In an unmanaged language, you will never free the memory allocated for the overwritten map.
Either way, initialization should be properly protected so that multiple threads do not run initialization code at the same time.
One reason: The first thread could be in the middle of initializing the HashMap, while a second thread comes a long, sees that map is not null, and merrily tries to use the partially-initialized data structure.
It is unsafe in multithreading case due to race condition.
But do you really need the lazy initialization for the map? If the map is going to be used anyway, seems you could just do eager initialization for it..
The above code isn't thread-safe, as others have mentioned, your map can be initialized twice. You may be tempted to try and fix the above code by adding some synchronization, this is known as "double checked locking", Here is an article that describes the problems with this approach, as well as some potential fixes.
The simplest solution is to make the field a static field in a separate class:
class HelperSingleton {
static Helper singleton = new Helper();
}
it can also be fixed using the volatile keyword, as described in Bill Pugh's article.
No, this code is not safe for use by multiple threads.
There is a race condition in the initialization of the map. For example, multiple threads could initialize the map simultaneously and clobber each others' writes.
There are no memory barriers to ensure that modifications made by a thread are visible to other threads. For example, each thread could use its own copy of the map because they never "see" the values written by another thread.
There is no atomicity to ensure that invariants are preserved as the map is accessed concurrently. For example, a thread that's performing a get() operation could get into an infinite loop because another thread rehashed the buckets during a simultaneous put() operation.
If you are using Java 6, use ConcurrentHashMap
ConcurrentHashMap JavaDoc

Java synchronized block vs concurrentHashMap vs Collections.synchronizedMap

Say If have a synchronized method and within that method, I update a hashmap like this:
public synchronized void method1()
{
myHashMap.clear();
//populate the hashmap, takes about 5 seconds.
}
now while the method1 is running and the hashmap is being re-populated, if there are other threads tring to get the value of the hashmap, I assume they will get blocked?
Now instead of using sync method, if I change hashmap to ConcurrentHashMap like below, what's the behaviour?
public void method1()
{
myConcurrentHashMap.clear();
//populate the hashmap, takes about 5 seconds.
}
what if i use Collections.synchronizedMap ? is it the same?
CHM(ConcurrentHashMap), instead of synchronizing every method on a common lock, restricting access to a single thread
at a time, it uses a finer-grained locking mechanism called lock striping to allow a greater degree of shared access. Arbitrarily many reading threads
can access the map concurrently, readers can access the map concurrently with
writers, and a limited number of writers can modify the map concurrently. The result
is far higher throughput under concurrent access, with little performance penalty for
single-threaded access.
ConcurrentHashMap, along with the other concurrent collections, further improve on
the synchronized collection classes by providing iterators that do not throw
ConcurrentModificationException, thus eliminating the need to lock the collection
during iteration.
As with all improvements, there are still a few tradeoffs. The semantics of methods
that operate on the entire Map, such as size and isEmpty, have been slightly
weakened to reflect the concurrent nature of the collection. Since the result of size
could be out of date by the time it is computed, it is really only an estimate, so size
is allowed to return an approximation instead of an exact count. While at first this
may seem disturbing, in reality methods like size and isEmpty are far less useful in
concurrent environments because these quantities are moving targets.
Secondly, Collections.synchronizedMap
It's just simple HashMap with synchronized methods - I'd call it deprecated dute to CHM
If you want to have all read and write actions to your HashMap synchronized, you need to put the synchronize on all methods accessing the HashMap; it is not enough to block just one method.
ConcurrentHashMap allows thread-safe access to your data without locking. That means you can add/remove values in one thread and at the same time get values out in another thread without running into an exception. See also the documentation of ConcurrentHashMap
you could probably do
volatile private HashMap map = newMap();
private HashMap newMap() {
HashMap map = new HashMap();
//populate the hashmap, takes about 5 seconds
return map;
}
public void updateMap() {
map = newMap();
}
A reader sees a constant map, so reads don't require synchronization, and are not blocked.

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.

Categories

Resources