Is this code multi-thread safe? - java

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

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().

Java visibility: final static non-threadsafe collection changes after construction

I found the following code snippet in luaj and I started to doubt that if there is a possibility that changes made to the Map after it has been constructed might not be visible to other threads since there is no synchronization in place.
I know that since the Map is declared final, its initialized values after construction is visible to other threads, but what about changes that happen after that.
Some might also realize that this class is so not thread-safe that calling coerce in a multi-threaded environment might even cause infinite loop in the HashMap, but my question is not about that.
public class CoerceJavaToLua {
static final Map COERCIONS = new HashMap(); // this map is visible to all threads after construction, since its final
public static LuaValue coerce(Object paramObject) {
...;
if (localCoercion == null) {
localCoercion = ...;
COERCIONS.put(localClass, localCoercion); // visible?
}
return ...;
}
...
}
You're correct that changes to the Map may not be visible to other threads. Every method that accesses COERCIONS (both reading and writing) should be synchronized on the same object. Alternatively, if you never need sequences of accesses to be atomic, you could use a synchronized collection.
(BTW, why are you using raw types?)
This code is actually bad and may cause many problems (probably not infinite loop, that's more common with TreeMap, with HashMap it's more likely to get the silent data loss due to overwrite or probably some random exception). And you're right, it's not guaranteed that the changes made in one thread will be visible by another one.
Here the problem may look not very big as this Map is used for caching purposes, thus silent overwrites or visibility lag doesn't lead to real problems (just two distinct instances of coersion will be used for the same class, which is probably ok in this case). However it's still possible that such code will break your program. If you like, you can submit a patch to LuaJ team.
Two options:
// Synchronized (since Java 1.2)
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
// Concurrent (since Java 5)
static final Map COERCIONS = new ConcurrentHashMap();
They each have their pros and cons.
ConcurrentHashMap pro is no locking. Con is that operations are not atomic, e.g. an Iterator in one thread and a call to putAll in another will allow iterator to see some of the values added.

Thread-safe resetting of an object's reference

The someParameters hashmap is loaded from a .csv file every twenty minutes or so by one thread and set by the setParameters method.
It is very frequently read by multiple threads calling getParameters: to perform a lookup translation of one value into a corresponding value.
Is the code unsafe and/ or the "wrong" way to achieve this (particularly in terms of performance)? I know about ConcurrentHashMap but am trying to get a more fundamental understanding of concurrency, rather than using classes that are inherrently thread-safe.
One potential risk I see is that the object reference someParameters could be reset whilst another thread is reading the copy, so the other thread might not have the latest values (which wouldn't matter to me).
public class ConfigObject {
private static HashMap<String, String> someParameters = new HashMap<String, String>();
public HashMap<String, String> getParameters(){
return new HashMap<String, String>(someParameters);
//to some thread which will only ever iterate or get
}
public void setParameters(HashMap<String, String> newParameters){
//could be called by any thread at any time
someParameters = newParameters;
}
}
There are two problems here
Visibility problem, as someParameters after update might not be visible to other thread, to fix this mark someParameters as volatile.
Other problem is performance one due to creating new HashMap in get method, to fix that use Utility method Collections.unmodifiableMap() this just wrap original map and disallowing put/remove method.
If I understand your problem correctly, you need to change/replace many parameters at once (atomically). Unfortunately, ConcurrentHashMap doesn't support atomic bulk inserts/updates.
To achieve this, you should use shared ReadWriteLock. Advantage comparing to Collections.synchronized... is that concurrent reads can be performed simultaneously: if readLock is acquired from some thread, readLock().lock() called from another thread will not block.
ReadWriteLock lock = new ReadWriteLock();
// on write:
lock.writeLock().lock();
try {
// write/update operation,
// e. g. clear map and write new values
} finally {
lock.writeLock().unlock();
}
// on read:
lock.readLock().lock();
try {
// read operation
} finally {
lock.readLock().unlock();
}

ConcurrentModifcationException when adding value to hashmap

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.

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

Categories

Resources