Skip to content

Initialization blocked by multi-threaded event publishing [SPR-16357] #20904

Closed
@spring-projects-issues

Description

Mark Paluch opened SPR-16357 and commented

Publishing events can block the container initialization in conjunction with event publishing from a different thread.

This can happen if events are published from a bean constructor while its bean is instantiated and events get published in a different thread while the constructed bean awaits completion of event publishing.

Consider following code:

@Component
class Foo {

	Foo(ApplicationEventPublisher publisher) throws Exception {

		Thread t = new Thread(() -> publisher.publishEvent(new Object()));
		t.start();
		t.join();
	}
}

The code above publishes an event in an other thread than the constructing thread while awaiting completion before the constructor progresses.

It leads to a thread state like:

"Thread-19@5373" daemon prio=5 tid=0x22 nid=NA waiting for monitor entry
  java.lang.Thread.State: BLOCKED
	 waiting for main@1315 to release lock on <0x17bd> (a java.util.concurrent.ConcurrentHashMap)
	  at org.springframework.context.event.AbstractApplicationEventMulticaster.getApplicationListeners(AbstractApplicationEventMulticaster.java:189)
	  at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:133)
	  at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:399)
	  at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:353)
	  at com.example.demo.Foo$1.run()
"main@1315" prio=5 tid=0xf nid=NA waiting (Thread calling initialization code)
  java.lang.Thread.State: WAITING
	 blocks Thread-19@5373
	  at java.lang.Object.wait(Object.java:-1)
	  at java.lang.Thread.join(Thread.java:1252)
	  at java.lang.Thread.join(Thread.java:1326)
	  at com.example.demo.Foo.<init>
	  at sun.reflect.NativeConstructorAccessorImpl.newInstance0(NativeConstructorAccessorImpl.java:-1)
	  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:163)
	  at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
	  at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:271)
	  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1270)
	  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
	  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
	  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)
	  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)
	  at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$87.1534495070.getObject(Unknown Source:-1)
	  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
	  - locked <0x17bd> (a java.util.concurrent.ConcurrentHashMap)
	  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)
	  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	  at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:758)

The example originates from reactive code in which a constructor is used to call initialization code using .block() for synchronization, see DATAMONGO-1841.


Affects: 5.0 GA

Issue Links:

0 votes, 8 watchers

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions