Hi I am getting the bug "Sequence of calls to java.util.concurrent.ConcurrentHashMap may not be atomic " when i am running find bug in my project for the below code.
public static final ConcurrentHashMap<String,Vector<Person>> personTypeMap = new ConcurrentHashMap<String, Vector<Person>>();
private static void setDefaultPersonGroup() {
PersonDao crud = PersonDao.getInstance();
List<Person> personDBList = crud.retrieveAll();
for (Person person : personDBList) {
Vector<Person> personTypeCollection = personTypeMap.get(person
.getGroupId());
if (personTypeCollection == null) {
personTypeCollection = new Vector<Person>();
personTypeMap.put(personTypeCollection.getGroupId(),
personTypeCollection);
}
personTypeCollection.add(person);
}
}
I am facing the problem at the line personTypeMap.put(personTypeCollection.getGroupId(), personTypeCollection);
Can any one help me to resolve the problem.
Java 1.5 introduced Concurrent classes in the java. util. concurrent package to overcome this scenario. ConcurrentHashMap is the Map implementation that allows us to modify the Map while iteration. The ConcurrentHashMap operations are thread-safe.
ConcurrentHashMap class is thread-safe i.e. multiple threads can operate on a single object without any complications. At a time any number of threads are applicable for a read operation without locking the ConcurrentHashMap object which is not there in HashMap.
What compound operations are you performing?
Map
contains a vector for a keyVector
if no value is foundSo this is a two step action and is compound, so it is unsafe.
Why are they not safe?
Because they are not atomic. Think of a scenario in which you have two threads.
Consider this timeline:
Thread 1 --- checks for == null -> true puts a new Vector
Thread 2 --- checks for ==null -> true puts a new Vector
Use putIfAbsent()
method on ConcurrentHashMap
, which provides you an atomic solution to what you are trying to perform.
ConcurrentHashMap#putIfAbsent()
References:
That findbugs message is telling you in the case of multi-threaded access it's not safe:
You're fetching something from personTypeMap
, checking to see if it's null
, then putting a new entry in if that's the case. Two threads could easily interleave here:
Thread1: get from map
Thread2: get from map
Thread1: check returned value for null
Thread1: put new value
Thread2: check returned value for null
Thread2: put new value
(Just as an example; in reality the ordering is not a given - the point is both threads get null
then act on it)
You should be creating a new entry, then calling personTypeMap.putIfAbsent()
as this guarantees atomicity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With