LRU

LRU 全称是 Least Recently Used,即最近最久未使用算法,它是页面置换算法的一种。

原理

如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。

LinkedHashMap介绍

LinkedHashMap继承于HashMap,与HashMap的区别是LinkedHashMap是有序的。

LinkedHashMap内部采用双向链表来记录插入顺序:

transient LinkedHashMapEntry head;
transient LinkedHashMapEntry tail;

LinkedHashMap并没有重写HashMap的put(key, value)方法,而是重写了newNode(hash, key, value, e),replacementNode(p, next),newTreeNode(hash, key, value, next),replacementTreeNode(p, next)方法,将key value插入到双向链表中。

LinkedHashMap重写了HashMap的get(key)方法,当accessOrder为true时,会将Node移至链表尾。

public V get(Object key) {
    Node e;
    if ((e = getNode(hash(key), key)) == null)
        return null;
    if (accessOrder)
        afterNodeAccess(e);
    return e.value;
}

LruCache

LruCache内部使用LinkedHashMap实现。

在LruCache的构造方法中会创建LinkedHashMap,其中accessOrder默认为true,这也就保证了在get(key)过程后会将结点放置队尾。

public class LruCache {

    private final LinkedHashMap map;

    public LruCache(int maxSize) {
        this.map = new LinkedHashMap(0, 0.75f, true);
    }

    public void resize(int maxSize) {}

    public final V get(K key) {}

    public final V put(K key, V value) {}

    public void trimToSize(int maxSize) {}

    public void V remove(K key) {}

    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}

    protected V create(K key) {}

    protected int sizeOf(K key, V value) {}
}

这里主要介绍下put(key, value)和get(key)两个方法。

put的过程很简单,如果map中有旧值,则回调entryRemoved(evicted, key, oldValue, newValue)方法。

最后会调用trimToSize(maxSize)方法,如果大小超过maxSize值,则会从头部移除结点。

public final V put(K key, V value) {
    V previous;
    synchronized (this) {
        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;
}

get的过程稍微复杂些,如果取到了value则直接返回。如果没取到,则调用create(key)方法尝试创建默认值,还要规避下冲突的情况。

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++;
    }

    /*
     * Attempt to create a value. This may take a long time, and the map
     * may be different when create() returns. If a conflicting value was
     * added to the map while create() was working, we leave that value in
     * the map and release the created value.
     */

    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;
    }
}

你可能感兴趣的:(LRU)