Well, the easiest way would be to just make your ServiceHandle
function synchronized
. Then only one thread could be inside at a time, and so, only a single instance of each bean would ever be created.
That works, but could be a bottleneck, when there are lots of threads asking for those beans: they'd end up all waiting for each other at the entrance to this function.
Here is one way to avoid that. It might look a little inolved, but what I like about it is that the most common path, after everything has been initialized does not require any synchronization or locking at all, and when a bean is being initialized, only threads, asking for that particular bean are forced to wait, while the others are unaffected:
class BeanHolder {
// Does not need to be volatile as long as once a bean is initialized it never changes again!
private Bean bean = null;
public Bean getBean(String name) {
if(bean == null) synchronized(this) {
if(bean == null) bean = init(name);
}
return bean;
}
}
ConcurrentHashMap<String, BeanHolder> beans = new ConcurrentHashMap<>();
Bean serviceHandle(String name) {
beans.putIfAbset(name, new BeanHolder());
return beans.get(name).getBean(name);
}