oscache 使用一个状态对象控制缓存更新的过程
其对象共有四个状态 1: 未赋值状态,2 正在更新状态 3 更新完成状态 4 取消更新状态
多线程操作时就是操作这个对象的几个状态
下面代码是oscache官方推荐的使用方法:
* // ---------------------------------------------------------------
* // Typical use with fail over
* // ---------------------------------------------------------------
* String myKey = "myKey";
* String myValue;
* int myRefreshPeriod = 1000;
* try {
* // Get from the cache
* myValue = (String) admin.getFromCache(myKey, myRefreshPeriod);
* } catch (NeedsRefreshException nre) {
* try {
* // Get the value (probably by calling an EJB)
* myValue = "This is the content retrieved.";
* // Store in the cache
* admin.putInCache(myKey, myValue);
* } catch (Exception ex) {
* // We have the current content if we want fail-over.
* myValue = (String) nre.getCacheContent();
* // It is essential that cancelUpdate is called if the
* // cached content is not rebuilt
* admin.cancelUpdate(myKey);
* }
* }
等待的线程栈:
"http-92-50" - Thread t@80
java.lang.Thread.State: WAITING
at java.lang.Object.wait(Native Method)
- waiting on <15be4b4> (a com.opensymphony.oscache.base.EntryUpdateState)
at java.lang.Object.wait(Object.java:485)
at com.opensymphony.oscache.base.Cache.getFromCache(Cache.java:278)
at com.opensymphony.oscache.base.Cache.getFromCache(Cache.java:221)
at com.opensymphony.oscache.general.GeneralCacheAdministrator.getFromCache(GeneralCacheAdministrator.java:151)
上述代码的admin.cancelUpdate(key); 发生线程阻塞的情况的状态:
如果同时多个线程对一个key发生访问,第一个线程得到锁后发现为空(状态为1)抛出nre异常并释放锁在catch里去更新数据,第二个线程进入由于发现别一个线程在更新(状态为2),于是waiting.其它线程则处于监视状态直到第二个线程释放状态对象 ,如果第一个线程更新时发生错误,于是cancelUpdate 状态改为(状态4),并释放锁通知第二个线程,它得到锁后发现状态是4则执行iscancel判断后的操作,操作状态改为4,释放锁后,第三个线程时来发现状态为4,于是等待,但这时也没有别的线程在执行更新对象操作了,自己也拿着锁,别人也进不来了,于是此线程一直会处于waiting状态,随着程序的长时间运行其它也取此key的监视线程会一直增加,浪费线程资源,严重时会导致内存溢出
我的解决办法改为admin.put(key,null); 第二个线程会将状态设为3,由于value为null,第三个线程取时会发现状态对象为1,会执行更新缓存操作,不会使第三个线程处于等待状态