在先前的文章里,我详细讨论了.NET缓存的简单用法。不过那点用途还只能是这一话题的“开胃酒”。现在,我们更进一步,在那篇文章所开发的缓存基础上添加条目在缓存中的过期功能。
清单A的内容就是上次我们开发的有关代码。
新缓存及其改进
为了创建定时缓存,我们首先得确定某个对象是否已经到期了。出于这篇文章讨论范围,我假设用户能够确定准确的对象超期日期。这样,在将来还可以再改进为允许在缓存中存放的对象自己确定它们的过期日期。
我们首先修改insertCachedObject方法以支持缓存中对象的过期功能。当对象插入缓存时,该方法会给用户提供一个对象过期日期。这个日期参数被称为dtExpiration。insertCachedObject方法则存储经由该参数传递的过期日期。完成这一目标有若干方法。例如,我们可以创建一个封装对象,其中包含了日期和对象属性。如果这样做的话,insertCachedObject方法就会创建封装对象的实例并提供给它两个属性。我们选择相比更简单些的第二个方案:创建和声明第2个哈希散列表,并且指定它同第一个哈希散列表并行运行。这第二个哈希散列表叫做htExpiration。
对 insertCachedObject 方法的修改请见清单B。
现在,我们需要想办法发现过期的条目。在通过getCachedObject方法发出请求时,简单而且也是最偷懒的办法是检查每个缓冲对象。因为直到发出处理请求才调出过期对象,所以这是一种较差的算法。而且很有可能在时间上具有一定的不确定性。虽然这些到期对象驻留在缓存里,可是它们消费着珍贵的内存资源,这对应用程序的性能具有极其不利的影响。
不用这种偷懒的办法,我们创建一个后台线程反复检查htExpiration哈希表。
于是我们创建一个名叫TheReaperThread的类,这个类有一个方法负责建立无限循环。该类还被声明为内部类,因为它只用在CustomCache对象的上下文环境内。该类的全部代码请见清单C。
你得对清单C中的Shared Constructor注意了,它负责创建新的线程并启动该线程。我们接下来创建测试程序保证缓存运行正常。测试程序见清单D,该程序是一个控制台程序,当然也可以用.NET Framework 把以上程序当作项目来创建。
小结
定时缓存就这样完全实现了。虽然在功能上还比较简单,而且不能通知缓存的用户条目在什么时候到期,也不允许对象确定它们自己的过期算法。不过在这种简单缓存的基础上,将来我们还可以讨论开发新的功能,比如分派、内存管理等等。
Listing A
'Defines a Public Class called CustomCache
Public Class CustomCache
'Declares the hashtable use to store everything put into the cache.
'Since ht is shared there it follows a Singleton pattern
Private Shared ht As System.Collections.Hashtable
'A shared Constructor runs when the class is referenced very first time.
Shared Sub New()
'Instantiates the Hashtable
ht = New Hashtable()
End Sub
'A private constructor prevents clients instantiating CustomCache Object
Private Sub New()
End Sub
'Shared method used to put objects into the cache
Public Shared Sub insertCachedObject(ByVal key As Object, ByVal o As Object)
ht.Add(key, o)
End Sub
'Shared method used to retrieve objects from the cache
Public Shared Function getCachedObject(ByVal key As Object) As Object
Return ht.Item(key)
End Function
End Class