Found one Java-level deadlock: ============================= "mondrian.rolap.RolapResultShepherd$executor_160": waiting to lock monitor 0x0000000043b2bf70 (object 0x0000000702080db0, a mondrian.rolap.MemberCacheHelper), which is held by "mondrian.rolap.RolapResultShepherd$executor_152" "mondrian.rolap.RolapResultShepherd$executor_152": waiting to lock monitor 0x00007f4e6c0751c8 (object 0x0000000702081270, a mondrian.rolap.MemberCacheHelper), which is held by "http-8182-11" "http-8182-11": waiting to lock monitor 0x0000000043b2bf70 (object 0x0000000702080db0, a mondrian.rolap.MemberCacheHelper), which is held by "mondrian.rolap.RolapResultShepherd$executor_152"
这意味着程序里面出现了死锁,这里牵扯到了三个线程,但是其中的两个线程都持有了一个锁并且希望锁住对方持有的锁,而第三个线程正在等待前两个线程中某个线程已经持有的锁,有了这个堆栈就很容易排查问题了,并且在堆栈信息中发现很多线程都在等待这两个线程中已经持有的锁,但是因为这两个线程已经处于死锁状态了,其他的线程只能同步的等待,这样继续在前端操作这些报表迟早把tomcat中的线程消耗完。 根据堆栈找到对应的代码,代码执行的是清理缓存的操作,但是缓存是对于每一个cube下的hierarchy创建的,因此根据具体的堆栈中的调用信息如下:
at mondrian.rolap.SmartMemberReader.flushCacheSimple(SmartMemberReader.java:577)
- waiting to lock <0x00000007020a8990> (a mondrian.rolap.MemberCacheHelper)
at mondrian.rolap.RolapCubeHierarchy$CacheRolapCubeHierarchyMemberReader.flushCacheSimple(RolapCubeHierarchy.java:883)
at mondrian.rolap.RolapCubeHierarchy.flushCacheSimple(RolapCubeHierarchy.java:458)
at mondrian.rolap.MemberCacheHelper.flushCache(MemberCacheHelper.java:166)
- locked <0x00000007020a8e50> (a mondrian.rolap.MemberCacheHelper)
at mondrian.rolap.RolapCubeHierarchy$CacheRolapCubeHierarchyMemberReader.flushCache(RolapCubeHierarchy.java:878)
at mondrian.rolap.RolapCubeHierarchy.flushCache(RolapCubeHierarchy.java:451)
最先进入的这个flushCache函数是hierarchy级别的缓存清理,它其实是调用它的成员变量reader对象的clearCache方法,这个reader用于读取这个hierarchy下的members,可以直接从数据源(关系 数据库)中读取,也维护了members的缓存,因此调用reader的clearCache方法也就是调用它的cache对象的方法,这个cache对象名为rolapCubeCacheHelper,类型为MemberCacheHelper,但是发现在reader中的clearCache方法执行的具体操作如下:
@Override
public void flushCache(){
super.flushCache();
rolapCubeCacheHelper.flushCache();
}
public void flushCache(){
synchronized( cacheHelper){
cacheHelper .flushCache();
}
}
这是父类的flushCache方法,它其实就是对成员变量的cacheHe