2014-12-03 91 views
0

我們有以下多段被調用的代碼。問題是它在100個請求spring registerBeanDefinition throws 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] 

一次投擲java.util.ConcurrentModificationException是否有人可以提供針對此問題的解決方案?

回答

0

問題是,兩個請求同時進來,他們都想註冊一個bean。要看看會發生什麼,我們必須查看DefaultListableBeanFactory的源代碼。在方法registerBeanDefinition(...)中有一個同步塊,其中兩個線程彼此等待完成。但在塊之後,調用方法resetBeanDefinition(...)。因此,當第一個線程完成同步塊並繼續執行復位方法時,第二個線程繼續執行同步塊。第一個線程繼續遍歷集合beanDefinitionNames(第714行),同時第二個線程將一個bean名稱添加到列表中(第669行)。所以你會得到一個異常。

如果兩個線程都想創建相同的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()); 
    } 
} 

編輯:發現異常的真正原因,解決方案仍然是相同的。

+0

你爲什麼認爲'containsBeanDefinition'運行在它自己的線程中? – 2014-12-03 20:22:06

+0

我在哪裏說的? :) – lmazgon 2014-12-03 20:22:59

+0

也許我誤解了。你在這裏談論的是什麼線程:_So如果你打到正確的時刻,你將會添加一個bean到集合中,而另一個線程正在迭代它。 – 2014-12-03 20:23:31

相關問題