From Usage_in_Java & Effective Java 2 , I do understand I need to have volatile
keyword, if the lazy initialization target is a single variable.
However, what about I'm perform multiple lazy initialization, and store them in a ConcurrentHashMap
? Does the Map
need to be volatile too?
Here's the code example.
public class Utils {
private static final Map<Integer, RemoteViews> remoteViewsMap = new ConcurrentHashMap<Integer, RemoteViews>();
public static RemoteViews getRemoteViews(int resourceId) {
RemoteViews remoteViews = remoteViewsMap.get(resourceId);
if (remoteViews == null) {
synchronized(remoteViewsMap){
remoteViews = remoteViewsMap.get(resourceId);
if (remoteViews == null) {
remoteViews = new RemoteViews("org.yccheok.gui", resourceId);
remoteViewsMap.put(resourceId, remoteViews);
}
}
}
return remoteViews;
}
}
Is the above code correct and thread safe?
There's no need for volatile
keyword since ConcurrentHashMap
being an implementation of ConcurrentMap
provides the following memory consistency effect:
actions in a thread prior to placing an object into a ConcurrentMap as a key or value happen-before actions subsequent to the access or removal of that object from the ConcurrentMap in another thread
However, that's not how you usually want to work with concurrent map. General pattern is as follows:
Object existing = concurrentMap.get(key);
// check if this key is already present
if (existing == null) {
Object newObject = new Object();
existing = concurrentMap.putIfAbsent(key, newObject); // atomic operation
// another thread might have already stored mapping for key
if (existing == null) {
return newObject;
}
}
return existing;
Note, it doesn't protect you from two threads simultaneously calling new Object()
(which can be an issue if creation of new object is expensive), but it allows you to avoid explicit synchronization alltogether.
Update: as for double-checked locking, in your case, it should look as follows:
Object value = concurrentMap.get(key);
if (value == null) {
synchronized (lock) {
value = concurrentMap.get(key);
if (value == null) {
value = new Object();
concurrentMap.put(key, value);
}
}
}
return value;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.