[转:http://www.blogjava.net/zddava/archive/2010/12/15/340731.html]
现在开始要介绍的从缓存中读取数据的过程,还是在GeneralCacheAdministrator#getFromCache(),这里有3个同名方法,还是找一个参数最多的:



























还是来到了Cache的#getFromCache():



















































































整个流程还是很好理解的,这里看一些细节,首先是#isStale()方法:
















其次是获取更新状态的方法:




















另外就是EntryUpdateState的startUpdate()方法,它会把过期缓存的状态设为UPDATE_IN_PROGRESS,这样更新缓存的线程就会执行更新操作了。









整个流程还是很好理解的,首先判断缓存是否过期,如果过期,那么会从更新状态缓存中查找更新状态,如果没查到那么创建一个,如果已经存在了,将引用计数加1。
如果缓存还没有进行更新,那么将更新状态设置为UPDATE_IN_PROGRESS,并且再次将引用计数加1,此时:
(1) 在设定完更新状态后,读取缓存的线程会将引用计数减1,如果没有线程此时再引用了那么在更新状态缓存中移除此项。
(2) 如果其他线程在更新缓存的时候会将引用计数减1,如果没有线程此时再引用了那么在更新状态缓存中移除此项。
这样,通过上边的两个过程,就将引用计数变为0了。
想法其实是非常好的,不过我在实际的测试中发现有时候其实并不是完全按照这个流程走下去的(当然很有可能是当初设计就是如此,允许发生报出这种异常):
线程1调用getFromCache()并发现缓存过期,更新状态为UPDATE_IN_PROGRESS后还没有调用#releaseUpdateState(),线程2执行#putInCache(),线程3执行#putInCache()。线程2更新完状态为UPDATE_COMPLETE后将引用计数减1,但是此时由于线程1还有一个引用计数,所以线程3更新状态时会在#completeUpdate()中抛出异常,因为此时的状态是UPDATE_COMPLETE。