栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

lru 缓存机制 redis java jdk LinkedHashMap 有界队列实现

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

lru 缓存机制 redis java jdk LinkedHashMap 有界队列实现

严格的lru算法

  1.基于读 更新时间, 2.并且要消除偶尔读对整体数据的影响. 也就是说要考虑 最近x小时内读的次数. 和 最近读的次数.

  实现上, 需要有个队列时刻维护好这个顺序关系. 但是redis没有这样实现, 避免内存浪费. 

  jdk这样实现了, 而且有个AccessOrder 来实现按读还是按写排序, AccessOrder=true按读.

redis的lru原理

   抽样算法 , 结合 pooling 缓存池技术

  详解Redis的LRU算法

那我能不能在下一轮移除Key时,利用好上一轮知晓的一些信息?

However if you think at this algorithm across its executions, you can see how we are trashing a lot of interesting data. Maybe when sampling the N keys, we encounter a lot of good candidates, but we then just evict the best, and start from scratch again the next cycle.

start from scratch太傻了。于是Redis又做出了改进:采用缓冲池(pooling)

当每一轮移除Key时,拿到了这个N个Key的idle time,如果它的idle time比 pool 里面的 Key的idle time还要大,就把它添加到pool里面去。这样一来,每次移除的Key并不仅仅是随机选择的N个Key里面最大的,而且还是pool里面idle time最大的,并且:pool 里面的Key是经过多轮比较筛选的,它的idle time 在概率上比随机获取的Key的idle time要大,可以这么理解:pool 里面的Key 保留了"历史经验信息"。

java 里的lru 

    LinkedHashMap removeEldestEntry 基于create/read的lru算法. 不是基于读的lru算法.

  accessOrder=true时

例子

  

public class Test {
    public static  class LruMap extends LinkedHashMap{

        public LruMap(){
            super(16,0.75f,true);
        }
        @Override
        protected boolean removeEldestEntry(Map.Entry eldest) {
            int size = size();
            return size >2;
        }
    }
    public static void main(String[] args) throws InterruptedException {

        Map map=new LruMap();

        map.put("1","1");
        map.put("2","2");

        Object o = map.get("1");
        System.out.println("after read key=1,value="+o+", map="+map.entrySet());

        map.put("3",3);

        System.out.println("after put key=3,value=3, map="+map.entrySet());

  }
}

输出结果

after read key=1,value=1, map=[2=2, 1=1]
after put key=3,value=3, map=[1=1, 3=3]

源代码解读

void afterNodeAccess(Node e) { // move node to last
    LinkedHashMap.Entry last;
    if (accessOrder && (last = tail) != e) {
        LinkedHashMap.Entry p =
            (LinkedHashMap.Entry)e, b = p.before, a = p.after;
        p.after = null;

        //将e从中间抽出来, 步骤1: 把e的a节点(after节点) 设置到e的b节点(before节点)上after上
        if (b == null)
            head = a;
        else
            b.after = a;
        //将e从中间抽出来,步骤2:  把e的e的b节点(before节点)上 设置到a节点(after节点) 的before上
        if (a != null)
            a.before = b;
        else
            last = b;
        
        // 将e节点放置到最末尾, 代表最新读取.
        if (last == null)
            head = p;
        else {
            p.before = last;
            last.after = p;
        }
        tail = p;
        ++modCount;
    }
}
accorder=false时,默认
 public class Test {

   public static  class LruMap extends LinkedHashMap{

        @Override
        protected boolean removeEldestEntry(Map.Entry eldest) {
            int size = size();
            return size >2;
        }
    }
    public static void main(String[] args) throws InterruptedException {

        Map map=new LruMap();

        map.put("1","1");
        map.put("2","2");

        Object o = map.get("1");
        System.out.println("after read key=1,value="+o+", map="+map.entrySet());

        map.put("3",3);

        System.out.println("after put key=3,value=3, map="+map.entrySet());


  }
}


after read key=1 ,value=1, map=[1=1, 2=2]
after put   key=3, value=3, map=[2=2, 3=3]

gava中的实现

剖析LinkedHashMap 和 LRU实现的种种_黄老师-的博客-CSDN博客_java lru

Guava LRU的具体实现

在Guava Cache的LRU实现中,它的双向链表并不是全局的。而是每个Segment(ConcurrentHashMap中的概念)中都有。

一共涉及到三个Queue其中包括:AccessQueue和WriteQueue,以及RecentQueue。其中AccessQueue和WriteQueue就是双向链表;而RecentQueue才是真正的Queue,它就是CocurrentLinkedQueue。

接下来我们简单分析下Guava Cache是如何通过这三个Queue来实现的LRU。

有界队列实现

   需要有个淘汰机制. 利用linkedHashMap可以实现

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/851726.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号