I'm trying to do a thread safe getter of a map value, which also creates the value if it does not exist:
private final static Map<String, MyObject> myMap = new HashMap<String, MyObject>();
public MyObject myGetter(String key) {
// Try to retrieve the object without synchronization
MyObject myObject = myMap.get(key);
if (myObject != null) {
return myObject;
}
// The value does not exist, so create a new object.
synchronized (myMap) {
myObject = myMap.get(key);
if (myObject == null) {
myObject = new MyObject(key);
myMap.put(key, myObject);
}
return myObject;
}
}
Note that the myMap
member variable is final, and it is not accessed anywhere else.
I do not want the MyObject to be created if not needed (some other patterns I have found suggest a pattern that may result in multiple creations for the same key).
I'm aware of the 'double check' anti-pattern, but I'm not sure if this code is applicable on that anti-pattern since it is not the member variable itself that is created here.
So, my question is if this still is a case of that anti-pattern, and if so: why?
Edit 1:
Judging from comments, one fix here would be to simply accept the 'performance impact' (a minor impact I guess), and just include the read in the synchronized block, like this:
private final static Map<String, MyObject> myMap = new HashMap<String, MyObject>();
public MyObject myGetter(String key) {
synchronized (myMap) {
MyObject myObject = myMap.get(key);
if (myObject == null) {
// The value does not exist, create a new object.
myObject = new MyObject(key);
myMap.put(key, myObject);
}
return myObject;
}
}
Also, I'm on Java 6, so the ConcurrentHashMap.computeIfAbsent is not an option here.