I have this singleton that creates objects, currently it looks like this:
public ApplicationManagerSingleton {
....
private Map<String, Thing> map = new HashMap<String, Thing>();
public Thing getThingById( String id ) {
Thing t = null;
if ( !map.contains(id) ) {
t = longAndCostlyInitializationOfThing();
map.put(id, t );
}
return map.get(id);
}
}
The obvious problem it has is, if two threads try to access the same thing, they may endup duplicating the thing.
So I used a lock:
public ApplicationManagerSingleton {
private Map<String, Thing> map = new HashMap<Sring, Thing>();
public Thing getThingById(String id ) {
synchronized( map ) {
if (!map.contains(id)) {
t = initialize....
}
map.put(id, t);
}
returns map.get(id);
}
}
But now that's worst because I'll be locking the map for a while each time a new resource is being created in demerit of the other threads wanting different things.
I'm pretty sure it can be better with Java 5 concurrent package. Can somebody point me in the right direction?
What I want to avoid is to lock the class or the map for other threads that are interested in other things.
I tried these solutions and they failed at some point in my implementation, not saying they wont work in other scenarios.
What I finally end up doing was to use a ConcurrentMap to check if the resource has been already requested or not. If not, it is created and stored somewhere else.
...
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
...
private ConcurrentMap<String, Boolean> created = new ConcurrentMap<>();
....
if ( created.putIfAbsent( id, Boolean.TRUE ) == null ) {
somewhereElse.put( id, createThing() );
}