oscache 的问题

一:现象:

系统页面无法打开,数据显示异常

二:原因分析:(代码分析,比较枯燥,请耐心查看)

 

在使用oscache的时候,为了减轻开发者的负担,同时也让代码具有更好的可读性,我们一般会使用annotation的方式来完成缓存的设值和取值

Code1

 

在调用当前方法的时候 会调用annotation拦截器的方法进行拦截,然后将返回值设置到缓存系统并返回。调研系统annotation拦截器调用的方法为CacheInterceptor.java doCache 方法

Code:2

 

问题出现在第二步和第三部的连贯上,在oscache中,EntryUpdateStatecache entry当前所处状态的表示,oscache尽量避免了使用synchronize,引入了许多状态参量。状态变迁图示如下:

假设在A线程调用getCache的时候,缓存条目不存在,或者过期,oscache会抛出一个异常,也就是臭名昭著的NeedsRefreshException,当这个异常出现,相应的EntryUpdateState的状态为updating(也就是更新中),此时如果B线程再来调用,就会block住,代码如下:

一个do  while循环。只有当A 调用 putInCache EntryUpdateState的状态变为complete,同时会调用updateState.notifyAll() 方法解除wait动作)或者cancelUpdate(状态此时的装变为cancelled,同时调用updateState.notify() 方法解除wait动作)方法才会打破这个循环。

getCachedObject中如果抛出这个异常,会怎么样呢?看代码:

Code4

从代码中,可以看到处理逻辑是捕捉这个异常,并将cachedObject设置为空,并返回。

 

因此就看第三步了,代码如下:

Code5

上面code4代码逻辑如下:

一:如果缓存返回值为空,则调用本地方法进行执行

二:如果执行结果为空,调用 cancelUpdate 方法将状态更新

三:如果执行结果不为空,则调用putInCache 方法将结果放入到缓存中

四:返回结果

请大家闭上眼睛思考下,上面一段代码

 

正常情况下,这段代码不会有问题,但是如果此时本地方法调用出现异常,会怎么样呢?也就是说pjp.proceed();这段代码抛出异常,此时当前A线程就永远不会更新状态,并进行notify操作,那么此时B线程就会一直在循环中,并堵塞以后所有的线程操作,最终结果就是操作会越来越缓慢,应用死掉。

解决方法其实也很简单,就是捕捉应用抛出的异常

Code6

后记:一路分析,抛出这个NeedsRefreshException 倒没有什么问题,关键还是那个状态问题,那么就要思考这个状态一定要么?如果不要可以么?如果可以的话,那么oscache当时为什么要这个状态呢?

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值