Scenario - Looks like this is timing issue. We have application lock (Lock#1) before calling getBean(), then there comes Spring framework ConcurrentHashMap (Lock#2). Threads are getting blocked on Lock#1 and Lock#2. Please find below snippets of thread dumps to prove the use case.
T1 - (Acquired Lock#1 and waiting for Lock#2)
"Catalina-utility-1" #85 prio=1 os_prio=0 tid=0x00007f9918034000 nid=0x33f0 waiting for monitor entry [0x00007f97f1ccd000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:213)
- waiting to lock <0x00000004df51aef8> (a java.util.concurrent.ConcurrentHashMap) (**-> At this place, waiting for Spring lock, Lock#2. Here it has already acquired Lock#1, and waiting for Lock#2** )
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1082)
at com.bmc.unifiedadmin.service.ABCServiceBeanContext.getService(ABCServiceBeanContext.java:53)
at com.bmc.unifiedadmin.service.ABCServicesFactory.getService(ABCServicesFactory.java:52) (**-> At this place, application semaphore have been acquired, Lock#1**)
T2 - (Acquired Lock#2 and waiting for Lock#1)
at java.util.concurrent.Semaphore.acquire(Semaphore.java:312) -> (**At this place, waiting for TSPS lock, Lock#1. Here it has already acquired Lock#2, and waiting for Lock#2**)
—
–
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1151)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1103)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:511)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
- locked <0x00000004df51aef8> (a java.util.concurrent.ConcurrentHashMap) ((**-> At this place, Lock#2 has been acquired**)
Comment From: rakeshvende
Hello there, any updates on this ticket?
Comment From: rakeshvende
Hello, I was waiting if we have any updates on this issue. Thanks.
Comment From: jhoeller
It's generally not advisable to wrap custom locks around getBean
calls, in particular if the same custom lock can also be acquired during the creation of specific beans, leading to lock ordering issues. You may choose to participate in Spring's singleton mutex (externally available via ConfigurableBeanFactory.getSingletonMutex()
, avoiding an actual deadlock by sharing the same mutex, but it's even better to not have an external lock at all if possible.