2

Here's the code:

HashMap<String, Bean> cachedBean;  
public Bean init(String name) {
     return new Bean(name);
}  

void ServiceHandle(String name) {
    if(cachedBean.get(name) == null) {
         Bean newBean = init(name);
         cachedBean.putIfAbsent(newBean);
    }
}

If 1000 clients call ServiceHandle with the same name, 1000 bean objects will be created, and only one of them will be put to the caced map. Is there a way to make sure that no matter how many times ServiceHandle will be called at the same time, only one bean will be created.

Cœur
  • 37,241
  • 25
  • 195
  • 267
nzomkxia
  • 1,219
  • 4
  • 16
  • 35

1 Answers1

2

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);
}
Dima
  • 39,570
  • 6
  • 44
  • 70