Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Cannot Reproduce
-
Affects Version/s: 1.5.6
-
Fix Version/s: None
-
Component/s: class generator
-
Labels:None
-
Number of attachments :
Description
If getInterfaces() is called from another thread, before CachedClass has been initialized, an exception maybe thrown. CachedClass should be put into the shared CACHED_CLASS_MAP after it has been initialized and not before. The initialize block may need to be synchronized to prevent a possible race condition.
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:70)
at org.codehaus.groovy.reflection.CachedClass.initialize(CachedClass.java:134)
at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:276)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:250)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:178)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:477)
— CachedClass.java:70 —
private Set interfaces;
public Set getInterfaces() {
if (interfaces == null) {
interfaces = new HashSet (0);
if (getCachedClass().isInterface())
interfaces.add(this);
Class[] classes = getCachedClass().getInterfaces();
for (int i = 0; i < classes.length; i++) {
final CachedClass aClass = ReflectionCache.getCachedClass(classes[i]);
if (!interfaces.contains(aClass))
interfaces.addAll(aClass.getInterfaces());
}
final CachedClass superClass = getCachedSuperClass();
if (superClass != null)
interfaces.addAll(superClass.getInterfaces());
}
return interfaces;
}
— ReflectionCache.java:276 —
CachedClass fasterCachedClass = null;
// Double-check put.
synchronized (CACHED_CLASS_MAP) {
ref = (SoftReference) CACHED_CLASS_MAP.get(klazz);
if (ref == null || (fasterCachedClass = (CachedClass) ref.get()) == null) {
CACHED_CLASS_MAP.put(klazz, new SoftReference(cachedClass));
} else {
// We must use the one that there first, we should be able to safely toss the one we made.
// By locking Class we would eliminate this race, but until the design is corrected we risk
// deadlock.
cachedClass = fasterCachedClass;
}
}
if (null == fasterCachedClass) {
// We've got a new CacheClass, now get loaded into the assignableMap.
cachedClass.initialize();
}
I have seen this on 1.5.6 when I have two classes that extend the same class and call newInstance() on each of the classes concurrently.
HitachiAccessHandleCollector extends HitachiDiscoveryCollector extends BaseCollector
Thread1 - HitachiAccessHandleCollector.newInstance
Thread2 - HitachiDiscoveryCollector.newInstance
Results in race condition and the stack trace as follows:
2010-08-28 08:30:00,018 ERROR collector-14 [com.akorri.bp.collectionserver.exception.DCSSException] Collector instantiation failed -> class com.akorri.bp.collectionserver.collectors.HitachiAccessHandleCollector
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:75)
at org.codehaus.groovy.reflection.CachedClass.initialize(CachedClass.java:134)
at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:276)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:250)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:729)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.initMetaClass(ScriptBytecodeAdapter.java:799)
at sun.reflect.GeneratedMethodAccessor137.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1105)
at org.codehaus.groovy.runtime.InvokerHelper.invokeStaticMethod(InvokerHelper.java:804)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeStaticMethodN(ScriptBytecodeAdapter.java:215)
at com.akorri.bp.collectionserver.collectors.BaseCollector.(BaseCollector.groovy:100)
at com.akorri.bp.collectionserver.collectors.HitachiDiscoveryCollector.(HitachiDiscoveryCollector.groovy)
at com.akorri.bp.collectionserver.collectors.HitachiAccessHandleCollector.(HitachiAccessHandleCollector.groovy)
at sun.reflect.GeneratedConstructorAccessor329.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at com.akorri.bp.collectionserver.collector.DcssService.collectNow(DcssService.java:281)