错误报警
[2019-01-07 15:30:25.237] [SIGTERM handler] [INFO] [out-flow-logger] - stopping, Step [5/5] Begin to do shutdownActions,for example spring context
Exception in thread "SaveThread-pool-1-thread-2" java.lang.IllegalStateException: The callinfo Cache is not alive (STATUS_SHUTDOWN)
at net.sf.ehcache.Cache$CacheStatus.checkAlive(Cache.java:4075)
at net.sf.ehcache.Cache.checkStatus(Cache.java:2766)
at net.sf.ehcache.Cache.get(Cache.java:1727)
at net.sf.ehcache.Cache.get(Cache.java:1707)
at com.vip.ads.service.common.queue.DiskQueue.pop(DiskQueue.java:59)
at com.vip.ads.service.common.queue.SaveThread.run(SaveThread.java:43)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "SaveThread-pool-1-thread-3" Exception in thread "SaveThread-pool-1-thread-1" java.lang.IllegalStateException: The callinfo Cache is not alive (STATUS_SHUTDOWN)
at net.sf.ehcache.Cache$CacheStatus.checkAlive(Cache.java:4075)
at net.sf.ehcache.Cache.checkStatus(Cache.java:2766)
at net.sf.ehcache.Cache.get(Cache.java:1727)
at net.sf.ehcache.Cache.get(Cache.java:1707)
at com.vip.ads.service.common.queue.DiskQueue.pop(DiskQueue.java:59)
at com.vip.ads.service.common.queue.SaveThread.run(SaveThread.java:43)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
java.lang.IllegalStateException: The callinfo Cache is not alive (STATUS_SHUTDOWN)
at net.sf.ehcache.Cache$CacheStatus.checkAlive(Cache.java:4075)
at net.sf.ehcache.Cache.checkStatus(Cache.java:2766)
at net.sf.ehcache.Cache.get(Cache.java:1727)
at net.sf.ehcache.Cache.get(Cache.java:1707)
at com.vip.ads.service.common.queue.DiskQueue.pop(DiskQueue.java:59)
at com.vip.ads.service.common.queue.SaveThread.run(SaveThread.java:43)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
从代码可以知道出错的地方在DiskQueue.pop。原因是Thread还没有执行完,cache就已经关闭了。
代码review
@Component
public class DiskQueue implements InitializingBean {
private static Ehcache cache;
@Resource(name = "ehcacheManager")
private CacheManager cacheManager;
private static AtomicLong index = new AtomicLong(0);
private static AtomicLong dealIndex = new AtomicLong(0);
private static long getNowIndex(){
return index.incrementAndGet();
}
private static long getNowDealIndex() {
return dealIndex.incrementAndGet();
}
private static void resetIndex() {
index.set(0);
}
private static void resetDealIndex() {
dealIndex.set(0);
}
public void push(List<CallInfo> callList) {
if(null != cache){
return;
}
Element element = new Element(getNowIndex(),callList);
cache.put(element);
}
public static List<CallInfo> pop() {
long nowDealIndex = dealIndex.get(); // 这里出了问题,index并没有增加
long nowIndex = index.get();
if(nowDealIndex > nowIndex){
resetIndex();
resetDealIndex();
return null;
}
if(cache == null){
return null;
}
Element element = cache.get(nowDealIndex); // 出错,cache已经被关闭
if(element==null){
return null;
}
Object obj = element.getObjectValue();
if(obj == null){
return null;
}
List<CallInfo> callInfos = (List<CallInfo>)obj;
cache.remove(nowDealIndex);
return callInfos;
}
@Override
public void afterPropertiesSet() throws Exception {
EhCacheCache tmpCache = (EhCacheCache) cacheManager.getCache("callinfo");
cache = tmpCache.getNativeCache();
}
}
问题点在于long nowDealIndex = dealIndex.get();
这行代码,当队列执行pop操作的时候,拿到的缓存下标一直都是初始化的下标0。第一次pop,是能够成功获取缓存对象的,获取完成就会把下标为0的Element从缓存中删除。那么之后的每次获取拿到的都是null。
看了下get()方法的源码:
public final Element get(Serializable key) throws IllegalStateException, CacheException {
return this.get((Object)key);
}
public final Element get(Object key) throws IllegalStateException, CacheException {
this.getObserver.begin();
this.checkStatus();
if (this.disabled) {
this.getObserver.end(GetOutcome.MISS_NOT_FOUND);
return null;
} else {
Element element = this.compoundStore.get(key);
if (element == null) {
this.getObserver.end(GetOutcome.MISS_NOT_FOUND);
return null;
} else if (this.isExpired(element)) {
this.tryRemoveImmediately(key, true);
this.getObserver.end(GetOutcome.MISS_EXPIRED);
return null;
} else {
if (!this.skipUpdateAccessStatistics(element)) {
element.updateAccessStatistics();
}
this.getObserver.end(GetOutcome.HIT);
return element;
}
}
}
public void end(T result) {
((LongAdder)this.counts.get(result)).increment();
if (!this.derivedStatistics.isEmpty()) {
long time = Time.time();
Iterator i$ = this.derivedStatistics.iterator();
while(i$.hasNext()) {
ChainedOperationObserver<? super T> observer = (ChainedOperationObserver)i$.next();
observer.end(time, result);
}
}
}
从源码看到,如果获取到的Element对象为空,就不仅仅是返回空对象这个简单的操作,还有this.getObserver.end(GetOutcome.MISS_NOT_FOUND)
。初步推断Ehcache中有自己的关闭机制,达到n次get()返回为空之后就会自动关闭cache。
有明确知道这个原因的小伙伴希望私信或评论一下我哈~共同学习进步。
网友评论