1. 程式人生 > >Android快取策略LruCahe原始碼解析,Lru到底是怎麼算的?

Android快取策略LruCahe原始碼解析,Lru到底是怎麼算的?

看前須知:

本篇文章是基於資料結構系列來寫的,也是他們的後續,請至少觀看過後兩篇文章的讀者,再來看這篇文章,推薦閱讀順序就是連結順序,如果你不看的話,這篇文章對你毫無意義,因為只是貼上了原始碼,標明瞭些註釋,沒錯文章的標題就是為了無恥的導流而存在的,因為大部分人只想瞭解Lru演算法或者LruCahe而進行搜尋,而LruCache關鍵的核心就是使用了LinkedHashMap,你必須先知道LinkedHashMap是怎樣的,而想了解LinkedHashMap你就需要了解他的父類Map和Collection介面下的LinkedList,所以請先觀看相關文章。

LruCache原始碼

public class LruCache<K, V> {
    private final LinkedHashMap<K, V> 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<K, V>(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<K, V> 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<K, V> snapshot() { return new LinkedHashMap<K, V>(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); } }