缓存淘汰算法-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)算法,也可以用来做缓存处理。
 

LRU(Least Recently Used)是一种常见的缓存淘汰算法,它的基本思想是:将最不常用的数据最先淘汰掉。 具体实现方式通常是将缓存空间划分为若干个桶(bucket),每个桶中存储一组数据,同时记录它们最后一次被访问的时间。当缓存空间满了,需要淘汰一些数据时,LRU算法会根据数据最近使用的频率和时间进行淘汰算法的核心思想是通过计数器(例如最近访问计数器)和哈希表(或排序列表)来实现。计数器用于记录每个数据项最后一次被访问的时间,哈希表或排序列表用于快速查找和删除数据项。 具体实现步骤如下: 1. 当缓存空间满了,需要淘汰一些数据时,遍历缓存中的所有数据项,并记录它们最后一次被访问的时间。 2. 根据时间戳和计数器的值,将数据项按照最近使用的频率进行排序。 3. 将排名最靠后的数据项从缓存中删除,并释放相应的空间。 4. 如果需要继续淘汰数据,重复步骤1-3,直到缓存空间不再满为止。 这种算法的优点是实现简单,易于理解和实现,并且具有较好的性能和效率。但是,它也有一些缺点,例如当缓存命中率较低时,需要频繁地进行淘汰和替换操作,导致缓存命中率进一步下降。此外,如果需要支持高并发访问,还需要考虑并发控制和线程安全等问题。 总之,LRU算法是一种常用的缓存淘汰算法,适用于需要快速响应和低延迟的应用场景。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值