我碰巧在一个使用mapperdao library的项目中工作 有时,它会抛出一个异常,表明该库不是线程安全的。我无法弄明白为什么 问题发生在this code:
type CacheKey = (Class[_], LazyLoad) private val classCache = new scala.collection.mutable.HashMap[CacheKey, (Class[_], Map[String, ColumnInfoRelationshipBase[_, Any, Any, Any]])] def proxyFor[ID, T](constructed: T with Persisted, entity: EntityBase[ID, T], lazyLoad: LazyLoad, vm: ValuesMap): T with Persisted = { (...) val key = (clz, lazyLoad) // get cached proxy class or generate it val (proxyClz, methodToCI) = classCache.synchronized { classCache.get(key).getOrElse { val methods = lazyRelationships.map(ci => ci.getterMethod.getOrElse( throw new IllegalStateException("please define getter method on entity %s . %s".format(entity.getClass.getName, ci.column)) ).getterMethod ).toSet if (methods.isEmpty) throw new IllegalStateException("can't lazy load class that doesn't declare any getters for relationships. Entity: %s".format(clz)) val proxyClz = createProxyClz(constructedClz, clz, methods) val methodToCI = lazyRelationships.map { ci => (ci.getterMethod.get.getterMethod.getName, ci.asInstanceOf[ColumnInfoRelationshipBase[T, Any, Any, Any]]) }.toMap val r = (proxyClz, methodToCI) classCache.put(key, r) r } } val instantiator = objenesis.getInstantiatorOf(proxyClz) val instance = instantiator.newInstance.asInstanceOf[DeclaredIds[ID] with T with MethodImplementation[T with Persisted]] (...) }
instantiator.newInstance
抛出java.lang.NoClassDefFoundError
一个类,它应该被动态编译并将其名称放入映射中。
这段代码对我来说似乎是线程安全的,因为地图上的任何操作都是在synchronized块中执行的。当地图返回一个尚未生成和编译的类名时,我无法弄清楚一个场景。我错过了什么吗?
另一个解释是该类已编译,但它对当前类加载器不可见。我不知道这是怎么发生的,为什么偶尔会发生这种情况。
更新: 轨迹跟踪如下:
java.lang.NoClassDefFoundError: Could not initialize class com.mypackage.MyClass_$2 at sun.reflect.GeneratedSerializationConstructorAccessor57.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:56) at com.googlecode.mapperdao.lazyload.LazyLoadManager.proxyFor(LazyLoadManager.scala:63) at com.googlecode.mapperdao.jdbc.impl.MapperDaoImpl.lazyLoadEntity(MapperDaoImpl.scala:338) at com.googlecode.mapperdao.jdbc.impl.MapperDaoImpl.$anonfun$toEntities$5(MapperDaoImpl.scala:301) at com.googlecode.mapperdao.internal.EntityMap.$anonfun$get$1(EntityMap.scala:46)
更新2:我终于找到了问题的根本原因。确实是一个并发问题,但在我粘贴的代码中却没有。它在MImpl class。 这里发生的是动态生成的类被正确编译,但由于MImpl class中的并发问题,它的初始化偶尔会失败。下次代码尝试实例化该类时最终会被JVM抛出NoClassDefFoundException。