📄 cache.java
字号:
package com.laoer.bbscs.util;
import java.util.*;
/**
* <p>Title: 天乙社区V5.0</p>
* <p>Description: BBS-CS天乙社区V5.0</p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: laoer.com</p>
* @author 龚天乙
* @version 5.0
*/
public class Cache
implements Cacheable {
protected static long currentTime = CacheTimer.currentTime;
protected HashMap cachedObjectsHash;
protected LinkedList lastAccessedList;
protected LinkedList ageList;
protected int maxSize = 128 * 1024;
protected int size = 0;
protected long maxLifetime = -1;
protected long cacheHits, cacheMisses = 0L;
public Cache() {
// Our primary data structure is a hash map. The default capacity of 11
// is too small in almost all cases, so we set it bigger.
cachedObjectsHash = new HashMap(103);
lastAccessedList = new LinkedList();
ageList = new LinkedList();
}
public Cache(int maxSize) {
this();
this.maxSize = maxSize;
}
public Cache(long maxLifetime) {
this();
this.maxLifetime = maxLifetime;
}
public Cache(int maxSize, long maxLifetime) {
this();
this.maxSize = maxSize;
this.maxLifetime = maxLifetime;
}
public int getSize() {
return size;
}
public int getMaxSize() {
return maxSize;
}
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
// It's possible that the new max size is smaller than our current cache
// size. If so, we need to delete infrequently used items.
cullCache();
}
public synchronized int getNumElements() {
return cachedObjectsHash.size();
}
public synchronized void add(Object key, Cacheable object) {
// Delete an old entry if it exists.
remove(key);
int objectSize = object.getSize();
// If the object is bigger than the entire cache, simply don't add it.
if (objectSize > maxSize * .90) {
return;
}
size += objectSize;
CacheObject cacheObject = new CacheObject(object, objectSize);
cachedObjectsHash.put(key, cacheObject);
// Make an entry into the cache order list.
LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key);
// Store the cache order list entry so that we can get back to it
// during later lookups.
cacheObject.lastAccessedListNode = lastAccessedNode;
// Add the object to the age list
LinkedListNode ageNode = ageList.addFirst(key);
// We make an explicit call to currentTimeMillis() so that total accuracy
// of lifetime calculations is better than one second.
ageNode.timestamp = System.currentTimeMillis();
cacheObject.ageListNode = ageNode;
// If cache is too full, remove least used cache entries until it is
// not too full.
cullCache();
}
public synchronized Cacheable get(Object key) {
// First, clear all entries that have been in cache longer than the
// maximum defined age.
deleteExpiredEntries();
CacheObject cacheObject = (CacheObject) cachedObjectsHash.get(key);
if (cacheObject == null) {
// The object didn't exist in cache, so increment cache misses.
cacheMisses++;
return null;
}
// The object exists in cache, so increment cache hits.
cacheHits++;
// Remove the object from it's current place in the cache order list,
// and re-insert it at the front of the list.
cacheObject.lastAccessedListNode.remove();
lastAccessedList.addFirst(cacheObject.lastAccessedListNode);
return cacheObject.object;
}
public synchronized void remove(Object key) {
CacheObject cacheObject = (CacheObject) cachedObjectsHash.get(key);
// If the object is not in cache, stop trying to remove it.
if (cacheObject == null) {
return;
}
// remove from the hash map
cachedObjectsHash.remove(key);
// remove from the cache order list
cacheObject.lastAccessedListNode.remove();
cacheObject.ageListNode.remove();
// remove references to linked list nodes
cacheObject.ageListNode = null;
cacheObject.lastAccessedListNode = null;
// removed the object, so subtract its size from the total.
size -= cacheObject.size;
}
/**
* Clears the cache of all objects. The size of the cache is reset to 0.
*/
public synchronized void clear() {
Object[] keys = cachedObjectsHash.keySet().toArray();
for (int i = 0; i < keys.length; i++) {
remove(keys[i]);
}
// Now, reset all containers.
cachedObjectsHash.clear();
cachedObjectsHash = new HashMap(103);
lastAccessedList.clear();
lastAccessedList = new LinkedList();
ageList.clear();
ageList = new LinkedList();
size = 0;
cacheHits = 0;
cacheMisses = 0;
}
public Object[] keys() {
return cachedObjectsHash.keySet().toArray();
}
public Object[] values() {
Object[] cacheObjects = cachedObjectsHash.values().toArray();
Object[] values = new Object[cacheObjects.length];
for (int i = 0; i < cacheObjects.length; i++) {
values[i] = ( (CacheObject) cacheObjects[i]).object;
}
return values;
}
public long getCacheHits() {
return cacheHits;
}
public long getCacheMisses() {
return cacheMisses;
}
private final void deleteExpiredEntries() {
//Check if expiration is turned on.
if (maxLifetime <= 0) {
return;
}
// Remove all old entries. To do this, we remove objects from the end
// of the linked list until they are no longer too old. We get to avoid
// any hash lookups or looking at any more objects than is strictly
// neccessary.
LinkedListNode node = ageList.getLast();
//If there are no entries in the age list, return.
if (node == null) {
return;
}
// Determine the expireTime, which is the moment in time that elements
// should expire from cache. Then, we can do an easy to check to see
// if the expire time is greater than the expire time.
long expireTime = currentTime - maxLifetime;
while (expireTime > node.timestamp) {
// Remove the object
remove(node.object);
// Get the next node.
node = ageList.getLast();
// If there are no more entries in the age list, return.
if (node == null) {
return;
}
}
}
private final void cullCache() {
// See if the cache size is within 3% of being too big. If so, clean out
// cache until it's 10% free.
if (size >= maxSize * .97) {
// First, delete any old entries to see how much memory that frees.
deleteExpiredEntries();
int desiredSize = (int) (maxSize * .90);
while (size > desiredSize) {
// Get the key and invoke the remove method on it.
remove(lastAccessedList.getLast().object);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -