Spring registerBeanDefinition抛出java.util.ConcurrentModificationException(Spring registerBeanDefiniti

编程入门 行业动态 更新时间:2024-10-11 13:24:29
Spring registerBeanDefinition抛出java.util.ConcurrentModificationException(Spring registerBeanDefinition throws java.util.ConcurrentModificationException)

我们有以下一段被多次调用的代码。 问题是它在100个请求中抛出一次java.util.ConcurrentModificationException

BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; boolean beanDefExists = registry.containsBeanDefinition(beanName); if (!beanDefExists) { BeanDefinitionBuilder beanDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz); beanDefBuilder.setScope(BeanDefinition.SCOPE_PROTOTYPE); beanDefBuilder.setLazyInit(false); registry.registerBeanDefinition(beanName, beanDefBuilder.getBeanDefinition()); } 13:18:10,728 INFO [stdout] (http-executor-threads - 33) java.util.ConcurrentModificationException: null 13:18:10,728 INFO [stdout] (http-executor-threads - 33) at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) ~[na:1.6.0_45] 13:18:10,729 INFO [stdout] (http-executor-threads - 33) at java.util.AbstractList$Itr.next(AbstractList.java:343) ~[na:1.6.0_45] 13:18:10,729 INFO [stdout] (http-executor-threads - 33) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resetBeanDefinition(DefaultListableBeanFactory.java:714) ~[spring-beans-3.2.2.RELEASE.jar:3.2.2.RELEASE] 13:18:10,729 INFO [stdout] (http-executor-threads - 33) at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:675) ~[spring-beans-3.2.2.RELEASE.jar:3.2.2.RELEASE]

有人可以为这个问题提供解决方案吗?

We have following piece of code that gets called multiple times. The issue is it is throwing java.util.ConcurrentModificationException once in 100 requests

BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; boolean beanDefExists = registry.containsBeanDefinition(beanName); if (!beanDefExists) { BeanDefinitionBuilder beanDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz); beanDefBuilder.setScope(BeanDefinition.SCOPE_PROTOTYPE); beanDefBuilder.setLazyInit(false); registry.registerBeanDefinition(beanName, beanDefBuilder.getBeanDefinition()); } 13:18:10,728 INFO [stdout] (http-executor-threads - 33) java.util.ConcurrentModificationException: null 13:18:10,728 INFO [stdout] (http-executor-threads - 33) at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) ~[na:1.6.0_45] 13:18:10,729 INFO [stdout] (http-executor-threads - 33) at java.util.AbstractList$Itr.next(AbstractList.java:343) ~[na:1.6.0_45] 13:18:10,729 INFO [stdout] (http-executor-threads - 33) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resetBeanDefinition(DefaultListableBeanFactory.java:714) ~[spring-beans-3.2.2.RELEASE.jar:3.2.2.RELEASE] 13:18:10,729 INFO [stdout] (http-executor-threads - 33) at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:675) ~[spring-beans-3.2.2.RELEASE.jar:3.2.2.RELEASE]

Can someone please provide a solution for this issue?

最满意答案

问题是,两个请求同时进入,他们都想注册一个bean。 要了解会发生什么,我们必须查看DefaultListableBeanFactory的源代码。 在方法registerBeanDefinition(...)有一个synchronized块,其中两个线程彼此等待完成。 但是在块之后,调用方法resetBeanDefinition(...) 。 因此,当第一个线程完成同步块并在重置方法内继续时,第二个线程继续执行同步块。 第一个线程继续循环遍历集合beanDefinitionNames (第714行),同时第二个线程将bean名称添加到列表中(第669行)。 所以你得到一个例外。

如果两个线程都想创建相同的bean,那么您显然只想创建一个并重用它,因此您必须将代码放在synchronized块中。 这样只有一个线程创建bean而另一个线程已经可以使用它。 另一方面,如果两个线程都创建不同的bean,则只需要同步registerBeanDefinition方法。

synchronized(this) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; boolean beanDefExists = registry.containsBeanDefinition(beanName); if (!beanDefExists) { BeanDefinitionBuilder beanDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz); beanDefBuilder.setScope(BeanDefinition.SCOPE_PROTOTYPE); beanDefBuilder.setLazyInit(false); registry.registerBeanDefinition(beanName, beanDefBuilder.getBeanDefinition()); } }

编辑:发现异常的真正原因,解决方案仍然是一样的。

The problem is, that two requests come in at the same time and they both want to register a bean. To see what happens, we must look at the source code of DefaultListableBeanFactory. In the method registerBeanDefinition(...) there is a synchronized block, where the two threads wait for each other to finish. But right after the block the method resetBeanDefinition(...) is called. So when the first thread finishes with the synchronized block and continues inside the reset method, the second thread goes on executing the synchronized block. The first thread goes on to loop through the collection beanDefinitionNames (line 714), while in the meantime the second thread adds a bean name to the list (line 669). So you get an exception.

If both threads want to create the same bean, then you obviously want to create only one and reuse it, so you have to put the code in a synchronized block. That way only one thread creates the bean and the other can already use it. On the other hand, if both threads create different beans, only the registerBeanDefinition method needs to be synchronized.

synchronized(this) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; boolean beanDefExists = registry.containsBeanDefinition(beanName); if (!beanDefExists) { BeanDefinitionBuilder beanDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz); beanDefBuilder.setScope(BeanDefinition.SCOPE_PROTOTYPE); beanDefBuilder.setLazyInit(false); registry.registerBeanDefinition(beanName, beanDefBuilder.getBeanDefinition()); } }

EDIT: Found the real reason for the exception, the solution is still the same.

更多推荐

本文发布于:2023-08-03 07:43:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1385387.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:抛出   registerBeanDefinition   Spring   java   throws

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!