📄 lrucache.java
字号:
_maxCapacity = max;
}
/* package private members */
/**
* If an entry exists in the cache, retrieve it regardless of
* whether it is expired. The caller should not modify the
* returned object.
*/
synchronized Entry getEntry(Object key) {
return (Entry)_keyOrder.get(key);
}
/* privates */
/**
* If an entry is expired, remove it from internal data structures, otherwise
* update the entry's timestamp and put it back in the LRU list. This method
* returns <code>true</code> if the entry was updated, or <code>false</code>
* if the entry was removed from the cache.
*/
private synchronized boolean update(Entry ent) {
if(ent.expired()) {
remove(ent.getKey());
return false; // the entry was not updated
}
_timeOrder.remove(ent);
ent.touch();
_timeOrder.put(ent,ent);
return true; // the entry was updated
}
/**
* Get an entry from the free entry pool and set the values. If the free
* entry pool is empty, a new entry will be created and returned.
*
* @see returnEntryToPool(Entry ent)
*/
private Entry getEntryFromPool(Object key, Object obj, long expirationTime, long lifespan) {
int last = _entryPool.size() - 1;
if(last >= 0) {
Entry ent = (Entry)_entryPool.remove(last);
ent.set(key,obj,expirationTime,lifespan);
return ent;
}
return new Entry(key,obj,expirationTime,lifespan);
}
/**
* Return an entry back into the free entry pool.
*
* @see getEntryFromPool(Object key, Object obj, long expirationTime, long lifespan)
*/
private void returnEntryToPool(Entry ent) {
ent.reset();
_entryPool.add(ent);
}
private int _maxCapacity = 32768;
private long _lifespan;
private long _timeout;
private TreeMap _timeOrder;
private HashMap _keyOrder;
private ArrayList _entryPool;
private static final long _DEFAULT_TIMEOUT = 1000; // 1-sec minimum timeout
private static final long _DEFAULT_LIFESPAN = 1000; // 1-sec minimum lifespan
/**
* Inner class for Cache entries. This Comparable class is
* consistent with equals.
*/
public class Entry implements Map.Entry, Comparable {
/**
* Create an entry. The timestamp for this entry is set at the
* time of creation. The exiprationTime is the duration after
* which this entry will expire, and the lifespan is the maximum
* lifespan in the cache.
*/
private Entry(Object key, Object obj, long expirationTimeout, long lifespan) {
set(key,obj,expirationTimeout,lifespan);
}
private void set(Object key, Object obj, long expirationTimeout, long lifespan) {
_key = key;
_obj = obj;
_created = System.currentTimeMillis();
_lastAccessed = _created;
_expirationTimeout = expirationTimeout;
_lifespan = lifespan;
}
/**
* Returns <code>true</code> if the entry is expired. An
* entry is considered to be expired if it hasn't been
* accessed for the duration of the <code>expirationTime</code>
* or if it has existed longer than its <code>lifespan</code>.
*/
public boolean expired() {
long currentTime = System.currentTimeMillis();
long expirationTime = _lastAccessed + _expirationTimeout;
long deathTime = _created + _lifespan;
boolean expired = false;
// If there is no overflow
if(expirationTime > 0) {
expired = currentTime >= expirationTime;
} else {
// If we overlow, the expiration time is an extremely large number
// that the current time will never reach, so the entry cannot
// be expired.
}
boolean dead = false;
// If there is no overflow
if(deathTime > 0) {
dead = currentTime >= deathTime;
} else {
// If we overlow, the death time is an extremely large number
// that the current time will never reach, so the entry cannot
// be expired.
}
// if we're expired or dead, we call
// that expired.
if(expired || dead) {
//System.out.println("Entry " + getKey() + " EXPIRED");
return true;
}
return false;
}
/**
* Update this entry's last accessed time so that
* it does not get evicted from the cache. This
* has to be done each time the object is updated
* in the cache.
*/
private void touch() {
_lastAccessed = System.currentTimeMillis();
}
/**
* Reset this entry's object references so that the contained
* values can get garbage collected.
*/
public void reset() {
_key = "";
_obj = "";
}
/**
* Get the key associated with this Entry. The <code>Object</code>
* returned is a <code>String</code>.
*/
public Object getKey() {
return _key;
}
/**
* Get the object stored in this Entry.
*/
public Object getValue() {
return _obj;
}
/**
* Set the object stored in this Entry.
*/
public Object setValue(Object obj) {
Object tmp = _obj;
_obj = obj;
return tmp;
}
/**
* Returns the <code>hashCode</code> for this object as
* described in {@link java.util.Map.Entry#hashCode
* Map.Entry.hashCode()}
*
* @see Map.Entry#hashCode()
*/
public int hashCode() {
return getKey().hashCode();
}
/**
* Get the last accessed timestamp for this object.
* The time is represented
* as the number of milliseconds since January 1, 1970,
* 00:00:00 GMT, the same as System.currentTimeMillis().
*/
protected long getLastAccessed() {
return _lastAccessed;
}
private long getCreationTime() {
return _created;
}
/**
* Return a key=value string for this entry.
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append(getKey() + "=" + getValue());
return buf.toString();
}
/**
* Tests for equality of this object and <code>entry</code>
* This function implements as described in
* {@link java.util.Map.Entry#equals Map.Entry.equals()}
*
* @throws ClassCastException if <code>entry</code> is not
* an <code>Entry</code> object.
*/
public boolean equals(Object entry) {
Entry ent = (Entry)entry;
if(getKey().equals(ent.getKey()))
return true;
return false;
}
/**
* Implement Comparable so we can sort entries. This function
* compares the last access times of the entries and imposes a total
* ordering on all entries. If two entries have the same timestamps,
* the entries' creation timestamps are compared, and if those
* are equal, the key's <code>hashCode()</code>
* values are compared to determine a total order.
*/
public int compareTo(Object obj) {
// If the keys are the same, we assume the entries are equal.
if(equals(obj)) return 0;
Entry ent = (Entry)obj;
long _ts = ent.getLastAccessed();
// This object is fresher than obj
if(_lastAccessed > _ts)
return -1;
// This object is not as fresh than obj
if(_lastAccessed < _ts)
return 1;
long _creation = ent.getCreationTime();
// This object is younger than obj
if(_creation > _ts)
return -1;
// This object is older than obj
if(_creation < _ts)
return 1;
// If the timestamps are the same, we compare the
// hash codes of the keys.
int mine = _key.hashCode();
int other = ent.getKey().hashCode();
if(mine > other)
return -1;
else if(mine < other)
return 1;
// In this most exceedingly rare occurance, we must ensure that
// we impose a total ordering.
return 1;
}
/* privates */
private Object _key;
private Object _obj;
private long _created;
private long _expirationTimeout;
private long _lifespan;
private long _lastAccessed;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -