📄 cache.java
字号:
package org.ehotsoft.yekki.util.cache;
import java.util.*;
import org.ehotsoft.yekki.util.link.LinkedList;
import org.ehotsoft.yekki.util.link.LinkedListNode;
public class Cache implements Cacheable {
protected static long currentTime = System.currentTimeMillis();
protected static CacheTimer timer = new CacheTimer(1000L);
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 ) {
if ( cachedObjectsHash.containsKey( key ) ) {
return;
}
int objectSize = object.getSize();
if ( objectSize > maxSize * .90 ) {
return;
}
size += objectSize;
CacheObject cacheObject = new CacheObject( object, objectSize );
cachedObjectsHash.put( key, cacheObject );
LinkedListNode lastAccessedNode = lastAccessedList.addFirst( key );
cacheObject.lastAccessedListNode = lastAccessedNode;
LinkedListNode ageNode = ageList.addFirst( key );
ageNode.timestamp = System.currentTimeMillis();
cacheObject.ageListNode = ageNode;
cullCache();
}
public synchronized Cacheable get( Object key ) {
deleteExpiredEntries();
CacheObject cacheObject = ( CacheObject )cachedObjectsHash.get( key );
if ( cacheObject == null ) {
cacheMisses++;
return null;
}
cacheHits++;
cacheObject.lastAccessedListNode.remove();
lastAccessedList.addFirst( cacheObject.lastAccessedListNode );
return cacheObject.object;
}
public synchronized void remove( Object key ) {
CacheObject cacheObject = ( CacheObject )cachedObjectsHash.get( key );
if ( cacheObject == null ) {
return;
}
cachedObjectsHash.remove( key );
cacheObject.lastAccessedListNode.remove();
cacheObject.ageListNode.remove();
cacheObject.ageListNode = null;
cacheObject.lastAccessedListNode = null;
size -= cacheObject.size;
}
public synchronized void clear() {
Object [] keys = cachedObjectsHash.keySet().toArray();
for ( int i=0; i<keys.length; i++ ) {
remove( keys[i] );
}
cachedObjectsHash.clear();
cachedObjectsHash = new HashMap( 103 );
lastAccessedList.clear();
lastAccessedList = new LinkedList();
ageList.clear();
ageList = new LinkedList();
size = 0;
cacheHits = 0;
cacheMisses = 0;
}
public Collection values() {
return Collections.unmodifiableCollection( cachedObjectsHash.values() );
}
public long getCacheHits() {
return cacheHits;
}
public long getCacheMisses() {
return cacheMisses;
}
private final void deleteExpiredEntries() {
if ( maxLifetime <= 0 ) {
return;
}
LinkedListNode node = ageList.getLast();
if ( node == null ) {
return;
}
long expireTime = currentTime - maxLifetime;
while( expireTime > node.timestamp ) {
remove( node.object );
node = ageList.getLast();
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 ) {
deleteExpiredEntries();
int desiredSize = ( int )( maxSize * .90 );
while ( size > desiredSize ) {
remove( lastAccessedList.getLast().object );
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -