本篇文章是基于数据结构系列来写的,也是他们的后续,请至少观看过后两篇文章的读者,再来看这篇文章,推荐阅读顺序就是链接顺序,如果你不看的话,这篇文章对你毫无意义,因为只是粘贴了源码,标明了些注释,没错文章的标题就是为了无耻的导流而存在的,因为大部分人只想了解Lru算法或者LruCahe而进行搜索,而LruCache关键的核心就是使用了LinkedHashMap,你必须先知道LinkedHashMap是怎样的,而想了解LinkedHashMap你就需要了解他的父类Map和Collection接口下的LinkedList,所以请先观看相关文章。
//LinkedList源码解析,推荐阅读,因为和LinkedHashMap息息相关
http://blog.csdn.net/omyrobin/article/details/78602043
//HashMap源码解析
http://blog.csdn.net/omyrobin/article/details/78614460
//LinkedHashMap源码解析,以及怎么知道那个元素是最近最少使用的
http://blog.csdn.net/omyrobin/article/details/78624798
public class LruCache<K, V> {
private final LinkedHashMap map;
/** Size of this cache in units. Not necessarily the number of elements. */
private int size;
private int maxSize;
private int putCount;
private int createCount;
private int evictionCount;
private int hitCount;
private int missCount;
/**
*构造函数,设置容量大小
*/
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
//创建了一个accessOrder为true的LinkedHashMap
this.map = new LinkedHashMap(0, 0.75f, true);
}
/**
* Sets the size of the cache.
*
* @param maxSize The new maximum size.
*/
public void resize(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
synchronized (this) {
this.maxSize = maxSize;
}
trimToSize(maxSize);
}
/**
*使用的还是map集合的get方法
*/
public final V get(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
/*
*
*/
V createdValue = create(key);
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;
mapValue = map.put(key, createdValue);
if (mapValue != null) {
// There was a conflict so undo that last put
map.put(key, mapValue);
} else {
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
/**
*放入元素,调用的还是map的put方法
*/
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, value);
}
//计算容量
trimToSize(maxSize);
return previous;
}
/**
*容量的计算方法,通过该方法可以知道容量是否超出,如果超出需要进行删除(最近最少使用)
*/
public void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
+ ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize) {
break;
}
//获取最近最少使用的元素(就是header.nxt的引用)
Map.Entry toEvict = map.eldest();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
//删除最近最少使用的元素
map.remove(key);
//重新计算size
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
/**
*
*/
public final V remove(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V previous;
synchronized (this) {
previous = map.remove(key);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null);
}
return previous;
}
/**
*
*/
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
/**
*
*/
protected V create(K key) {
return null;
}
private int safeSizeOf(K key, V value) {
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "=" + value);
}
return result;
}
/**
*
*/
protected int sizeOf(K key, V value) {
return 1;
}
/**
* Clear the cache, calling {@link #entryRemoved} on each removed entry.
*/
public final void evictAll() {
trimToSize(-1); // -1 will evict 0-sized elements
}
/**
*
*/
public synchronized final int size() {
return size;
}
/**
*最大size
*/
public synchronized final int maxSize() {
return maxSize;
}
/**
*
*/
public synchronized final int hitCount() {
return hitCount;
}
/**
*
*/
public synchronized final int missCount() {
return missCount;
}
/**
* Returns the number of times {@link #create(Object)} returned a value.
*/
public synchronized final int createCount() {
return createCount;
}
/**
* Returns the number of times {@link #put} was called.
*/
public synchronized final int putCount() {
return putCount;
}
/**
* Returns the number of values that have been evicted.
*/
public synchronized final int evictionCount() {
return evictionCount;
}
/**
* Returns a copy of the current contents of the cache, ordered from least
* recently accessed to most recently accessed.
*/
public synchronized final Map snapshot() {
return new LinkedHashMap(map);
}
@Override public synchronized final String toString() {
int accesses = hitCount + missCount;
int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
maxSize, hitCount, missCount, hitPercent);
}
}