CachePolicy在JDBM有两种现成的实现,一个是MRU(Most Recently Used),另一个是SoftCache。
MRU用Hashtable来保存缓存对象,每一个对象都维护它的next和previous对象,这样形成一个双向链表。之所以采用Hashtable,应该是考虑同步的问题。
MRU的原则就是最多使用的缓存对象放在链表的最末尾,最少使用的缓存对象放在链表的头部。新加的缓存对象都是放在尾部,如果有size的限制,那么头部的缓存对象会随找size的限制会被purge,这样可以加入新的缓存对象。每次purge的时候都会调用注册的Listeners,如果抛出异常则这个缓存对象不会被删除。
CachePolicyListener listener;
for (int i=0; i<listeners.size(); i++) {
listener = (CachePolicyListener)listeners.elementAt(i);
listener.cacheObjectEvicted(entry.getValue());
}
注意传入到cacheObjectEvicted中的变量是一个value,即处理的是缓存的对象而不是缓存项(CacheEntry)。
SoftCache利用了java的一个类SoftReference(详见内存优化的两个参数SoftReference和WeakReference)。它维护了两个map,一个是MRU对象_internal,另一个是Map对象_cacheMap,用于缓存SoftReference。
put方法中有:_cacheMap.put(key, new Entry(key, value, _clearQueue));
Entry类如下:
private static class Entry extends SoftReference {
private final Object _key;
/**
* Constructor that uses <code>value</code> as the soft
* reference's referent.
*/
public Entry(Object key, Object value, ReferenceQueue queue) {
super(value, queue);
_key = key;
}
/**
* Gets the key
* @return the key associated with this value.
*/
final Object getKey() {
return _key;
}
/**
* Gets the value
* @return the value; null if it is no longer accessible
*/
final Object getValue() {
return this.get();
}
}
get方法:
public Object get(Object key) {
// first try the internal cache.
Object value = _internal.get(key);
if (value != null) {
return value;
}
// poll and remove cleared references.
removeClearedEntries();
Entry entry = (Entry)_cacheMap.get(key);
if (entry == null) { // object is not in cache.
return null;
}
value = entry.getValue();
if (value == null) { // object was in cache, but it was cleared.
return null;
}
// we have the object. so we try to re-insert it into internal cache
try {
_internal.put(key, value);
} catch (CacheEvictionException e) {
// if the internal cache causes a fuss, we kick the object out.
_cacheMap.remove(key);
return null;
}
return value;
}
MRU的使用具体可以看CacheRecordManager类,它的创建在Provider类中:
RecordManager recman = new BaseRecordManager( name );
MRU cache = new MRU( cacheSize );
recman = new CacheRecordManager( recman, cache );
如果使用Factory获取RecordMagener
RecordManagerFactory.createRecordManager( String name, Properties options ),
得到的就是CacheRecordManager,如果非得使用BaseRecordManager:
RecordManager recman = new BaseRecordManager( name );
直接new一个即可。