Spring registerBeanDefinition抛出java.util.ConcurrentModificationException

Spring registerBeanDefinition抛出java.util.ConcurrentModificationException,spring,Spring,我们有下面一段代码,它被多次调用。问题是它每100个请求中就抛出一次java.util.ConcurrentModificationException BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; boolean beanDefExists = registry.containsBeanDefinition(beanName); if (!beanDefExists) {

我们有下面一段代码,它被多次调用。问题是它每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());
    }

有人能为这个问题提供一个解决方案吗?

问题是,两个请求同时出现,它们都想注册一个bean。要了解发生了什么,我们必须查看的源代码。在方法registerBeanDefinition中。。。有一个同步块,其中两个线程等待对方完成。但是在阻塞之后,方法resetBeanDefinition。。。被称为。因此,当第一个线程完成同步块并在reset方法中继续时,第二个线程继续执行同步块。第一个线程继续循环通过集合beanDefinitionNames行714,同时第二个线程向列表行669添加一个bean名称。所以你得到了一个例外

如果两个线程都想创建同一个bean,那么显然您只想创建一个bean并重用它,因此您必须将代码放在一个同步块中。这样,只有一个线程创建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());
    }
}

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

为什么您认为ContainesBeanDefinition在其自己的线程中运行?我在哪里说的也许我误解了。你在这里说的是什么线程:所以,如果你点击正确的时机,你会在另一个线程迭代时向集合添加一个bean。?我的意思是,另一个请求进入,它在自己的线程中运行-我猜这是一个web应用程序。我明白了。谢谢你的澄清。
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());
    }
}