Skip to content

Creating ApplicationContexts from multiple threads causes ConcurrentModificationException [SPR-10543] #15173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue May 8, 2013 · 6 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented May 8, 2013

James Shaw opened SPR-10543 and commented

See testcase to reproduce. Backtrace:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myChild' defined in class MyConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public MyChild MyConfiguration.myChild()] threw exception; nested exception is java.util.ConcurrentModificationException
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:581)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1031)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:927)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:490)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
	at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:73)
	at Test$1.run(Test.java:15)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:722)
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public MyChild MyConfiguration.myChild()] threw exception; nested exception is java.util.ConcurrentModificationException
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:181)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:570)
	... 16 more
Caused by: java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
	at java.util.ArrayList$Itr.next(ArrayList.java:791)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:587)
	at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1338)
	at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:904)
	at org.springframework.beans.factory.support.AbstractBeanFactory.containsBean(AbstractBeanFactory.java:370)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.factoryContainsBean(ConfigurationClassEnhancer.java:323)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:261)
	at MyConfiguration$$EnhancerByCGLIB$$15938d63.myChild(<generated>)
	at sun.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160)
	... 17 more

I've also seen deadlocks occurring when running my integration tests in parallel, but I've been unable to reduce those to a test case.


Affects: 3.2.2

Attachments:

Issue Links:

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

This isn't surprising since we generally expect an ApplicationContext to fully refresh in a single thread before getting exposed to other threads. In other words, it's only meant to be accessed concurrently after the refresh phase.

We have plans to revisit this for Spring Framework 4.0, but for the time being, I'm afraid your scenario is simply not supported.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

James Shaw commented

Many thanks for your feedback Juergen. Just to check I understand correctly, you're saying that Spring 3 doesn't support separate ApplicationContexts being created in separate threads? Can you explain what state is being shared between ApplicationContext instances and why?

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

No, I just meant to say that any given ApplicationContext should not get exposed to other threads before its refresh phase completed. Independent ApplicationContexts should be able to bootstrap concurrently just fine, as long as they are not sharing any kind of configuration state.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

James Shaw commented

Ok, but in my test case, I don't think I'm sharing ApplicationContexts between threads, so it should bootstrap successfully, no?

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented May 16, 2013

Juergen Hoeller commented

Sorry, didn't notice your attached repro project before...

I think I know what's going on there now: You're using the same @Configuration class for all of your ApplicationContexts, all running in the same ClassLoader. Due to a limitation in our use of CGLIB, this may indeed lead to side effects for concurrent ApplicationContexts; in fact, sharing a configuration class does mean sharing some configuration state in Spring 3.x. The effect that you're seeing is slightly odd even with that CGLIB cause in mind, but still, I'm pretty sure that it is the cause.

This has been addressed for 4.0 M1 in the form of reworked configuration class processing which uses instance state only now - and therefore should not lead to any sharing between concurrent ApplicationContexts, even if they register the very same @Configuration class in the same ClassLoader there. See #14941 for the original issue.

Hope that helps,

Juergen

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented May 16, 2013

Juergen Hoeller commented

I assume that this issue has been addressed along with #14941. Please reopen it if this still doesn't work for you against 4.0 M1 (to be released tomorrow).

Juergen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants