HashMap在多线程下导致死循环的原因可以参考http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html
在多线程环境下,各个线程的Hibernate Session不同,使用Hibernate查询一个实体时,非常罕见的出现了一次,堆栈如下
"pool-130-thread-6" prio=10 tid=0x00002aab010ed800 nid=0x3aba runnable [0x000000004addf000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.put(HashMap.java:391)
at org.hibernate.engine.StatefulPersistenceContext.addCollection(StatefulPersistenceContext.java:764)
at org.hibernate.engine.StatefulPersistenceContext.addUninitializedCollection(StatefulPersistenceContext.java:733)
at org.hibernate.type.CollectionType.getCollection(CollectionType.java:609)
at org.hibernate.type.CollectionType.resolveKey(CollectionType.java:408)
at org.hibernate.type.CollectionType.resolve(CollectionType.java:402)
at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:120)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:854)
at org.hibernate.loader.Loader.doQuery(Loader.java:729)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1860)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:48)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:42)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3049)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:399)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:375)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:139)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:98)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:878)
at org.hibernate.impl.SessionImpl.immediateLoad(SessionImpl.java:836)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:66)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150
跟踪调试,发现在多个线程中确实存在相同的session,这些session存在于持久化实体中的CGLIB代理里面
由于这些实体对象是在进入多线程环境之前就已经查询出来了,但是他们关联的对象都是lazy-load,所以都以CGLIB的形式存在与这些实体对象中。于是,在多线程环境下,尽管重新生成了新的session,但是通过实体延迟加载时就会使用之前的session,这样就导致了一个错误的用法:并发使用Hibernate的session