Preface: I’m know that in most cases using a volatile field won’t yield any measurable performance penalty, but this question is more theoretical and targeted towards a design with an extremly high corrency support.
I’ve got a field that is a List<Something> which is filled after constrution. To save some performance I would like to convert the List into a read only Map. Doing so at any point requires at least a volatile Map field so make changes visible for all threads.
I was thinking of doing the following:
Map map;
public void get(Object key){
if(map==null){
Map temp = new Map();
for(Object value : super.getList()){
temp.put(value.getKey(),value);
}
map = temp;
}
return map.get(key);
}
This could cause multiple threads to generate the map even if they enter the get block in a serialized way. This would be no big issue, if threads work on different identical instances of the map. What worries me more is:
Is it possible that one thread assigns the new temp map to the map field, and then a second thread sees that map!=null and therefore accesses the map field without generating a new one, but to my suprise finds that the map is empty, because the put operations where not yet pushed to some shared memory area?
Answers to comments:
- The threads only modify the temporary map after that it is read only.
- I must convert a List to a Map because of some speical JAXB setup which doesn’t make it feasable to have a Map to begin with.
Yes, this is absolutely possible; for example, an optimizing compiler could actually completely get rid of the local
tempvariable, and just use themapfield the whole time, provided it restoredmaptonullin the case of an exception.Similarly, a thread could also see a non-null, non-empty
mapthat is nonetheless not fully populated. And unless yourMapclass is carefully designed to allow simultaneous reads and writes (or usessynchronizedto avoid the issue), you could also get bizarre behavior if one thread is calling itsgetmethod while another is calling itsput.