Reputation: 339
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.
Upvotes: 10
Views: 6274
Reputation: 1
In your case, your code should looks like this:
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) {
// the putIfAbsent works in the same way of your
//previous code, but in atomic way
Vector<Person> personTypeCollection = personTypeMap.putIfAbsent(person
.getGroupId());
personTypeCollection.add(person);
}
}
Upvotes: 0
Reputation: 41965
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:
Upvotes: 14
Reputation: 76908
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.
Upvotes: 3