缓存淘汰算法-LRU

1.LRU(Least Recently Used) 表示最近最久未使用,其主要有四种实现(LRU、LRU-K、Two Queue、Mutiply Queue)

LRU原理:当缓存空间满了的时候,若是在往里边插入数据,此时需要根据最近最久未使用规则删除最不可能访问的元素,即删除最长时间       没有被访问到的数据。

LRU设计以及实现:

**1.使用LinkedHashMap实现经典LRU**
        LinkedHashMap是HashMap加双链表的形式,其访问也是有顺序的访问,其本身有removeEldestEntry方法,其作用就是当指定空间已满,其会删除最近最久未被使用的元素,其默认返回是false,我们重修此方法让其放回true。其实现如下所示:

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
    private final int maxCapacity;

    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

    private final Lock lock = new ReentrantLock();

    public LRULinkedHashMap(int maxCapacity) {
        super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
        this.maxCapacity = maxCapacity;
    }

    @Override
    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
        return size() > maxCapacity;
    }
    @Override
    public boolean containsKey(Object key) {
        try {
            lock.lock();
            return super.containsKey(key);
        } finally {
            lock.unlock();
        }
    }
    @Override
    public V get(Object key) {
        try {
            lock.lock();
            return super.get(key);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public V put(K key, V value) {
        try {
            lock.lock();
            return super.put(key, value);
        } finally {
            lock.unlock();
        }
    }

    public int size() {
        try {
            lock.lock();
            return super.size();
        } finally {
            lock.unlock();
        }
    }

    public void clear() {
        try {
            lock.lock();
            super.clear();
        } finally {
            lock.unlock();
        }
    }

    public Collection<Map.Entry<K, V>> getAll() {
        try {
            lock.lock();
            return new ArrayList<Map.Entry<K, V>>(super.entrySet());
        } finally {
            lock.unlock();
        }
    }
}


当存在热点数据时,LRU的效率很好,但偶发性的、周期性的批量操作会导致LRU命中率急剧下降,缓存污染情况比较严重。
**2.LRU-K原理以及实现**
        其实LRU本身就是LRU-1,最常用的还有LRU-2,其原理是多维护一个队列,当数据被访问则先放入队列,当访问次数达到K次,则将其从队列拿出放入缓存中,其目的就是解决了LRU-1的缓存污染情况,但其也想对需要更多的内存空间去记录历史访问数据。其本质也类似LRU。

**3. Two Queue**
        双队列模式原理就是,使用两个队列,一个是LRU队列,一个是FIFO队列,当数据被访问时,先放入FIFO队列,当数据在次被访问时,则将其放入LRU队列,两个队列都有自己的淘汰规则,其主要缺点也是需要多维护一个队列。
 **4.Mutiply Queue**
   多队列模式,使用多个不同优先级的队列来处理数据,Q1.Q2.......Qn,Q-history,从Q1到Qn,优先级依次升到,当数据在低优先级队列被访问到一定次数,则放入相对优先级更高的一个队列,当数据长时间在高优先级队列未被访问,则放入低优先级队列,每个队列按照LRU淘汰规则淘汰数据,将淘汰数据索引放入Q-history队列,当那放入队列,否则按照LRU规则进行淘汰。其主要缺点是需要维护多个优先级队列,消耗内存过高,复杂度过高。

**5.LRU算法对比**
   

对比点对比
命中率LRU-2>MQ(2)>2Q>LRU
复杂度LRU-2>MQ(2)>2Q>LRU
代价LRU-2  > MQ(2) > 2Q > LRU

**6.总结**
        总的来说每个算法个各有利弊,有的复杂度第,又的命中率高,按照不同的需求选取不同的算法,相对LRU还有LFU(Least Frequently Used)算法,也可以用来做缓存处理。
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值