Java缓存(LRU,FIFO)
创始人
2024-06-03 23:14:13
0

dc22fad5695f460cbb3127906f3e0b6b.gif现在软件或者网页的并发量越来越大了,大量请求直接操作数据库会对数据库造成很大的压力,处理大量连接和请求就会需要很长时间,但是实际中百分之80的数据是很少更改的,这样就可以引入缓存来进行读取,减少数据库的压力。

 

 

常用的缓存有Redis和memcached,但是有时候一些小场景就可以直接使用Java实现缓存,就可以满足这部分服务的需求。

 

缓存主要有LRU和FIFO,LRU是Least Recently Used的缩写,即最近最久未使用,FIFO就是先进先出,下面就使用Java来实现这两种缓存。

 

LRU

LRU缓存的思想

 

固定缓存大小,需要给缓存分配一个固定的大小。

每次读取缓存都会改变缓存的使用时间,将缓存的存在时间重新刷新。

需要在缓存满了后,将最近最久未使用的缓存删除,再添加最新的缓存。

按照如上思想,可以使用LinkedHashMap来实现LRU缓存。

 

这是LinkedHashMap的一个构造函数,传入的第三个参数accessOrder为true的时候,就按访问顺序对LinkedHashMap排序,为false的时候就按插入顺序,默认是为false的。

当把accessOrder设置为true后,就可以将最近访问的元素置于最前面,这样就可以满足上述的第二点。

 

/**

 * Constructs an empty LinkedHashMap instance with the

 * specified initial capacity, load factor and ordering mode.

 *

 * @param initialCapacity the initial capacity

 * @param loadFactor the load factor

 * @param accessOrder the ordering mode - true for

 * access-order, false for insertion-order

 * @throws IllegalArgumentException if the initial capacity is negative

 * or the load factor is nonpositive

 */

public LinkedHashMap(int initialCapacity,

                     float loadFactor,

                     boolean accessOrder) {

    super(initialCapacity, loadFactor);

    this.accessOrder = accessOrder;

}

这是LinkedHashMap中另外一个方法,当返回true的时候,就会remove其中最久的元素,可以通过重写这个方法来控制缓存元素的删除,当缓存满了后,就可以通过返回true删除最久未被使用的元素,达到LRU的要求。这样就可以满足上述第三点要求。

 

protected boolean removeEldestEntry(Map.Entry eldest) {

    return false;

}

由于LinkedHashMap是为自动扩容的,当table数组中元素大于Capacity * loadFactor的时候,就会自动进行两倍扩容。但是为了使缓存大小固定,就需要在初始化的时候传入容量大小和负载因子。

为了使得到达设置缓存大小不会进行自动扩容,需要将初始化的大小进行计算再传入,可以将初始化大小设置为(缓存大小 / loadFactor) + 1,这样就可以在元素数目达到缓存大小时,也不会进行扩容了。这样就解决了上述第一点问题。

 

通过上面分析,实现下面的代码

 

import java.util.LinkedHashMap;

import java.util.Map;

import java.util.Set;

 

public class LRU1 {

    private final int MAX_CACHE_SIZE;

    private final float DEFAULT_LOAD_FACTORY = 0.75f;

 

    LinkedHashMap map;

 

    public LRU1(int cacheSize) {

        MAX_CACHE_SIZE = cacheSize;

        int capacity = (int)Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTORY) + 1;

        /*

         * 第三个参数设置为true,代表linkedlist按访问顺序排序,可作为LRU缓存

         * 第三个参数设置为false,代表按插入顺序排序,可作为FIFO缓存

         */

        map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTORY, true) {

            @Override

            protected boolean removeEldestEntry(Map.Entry eldest) {

                return size() > MAX_CACHE_SIZE;

            }

        };

    }

 

    public synchronized void put(K key, V value) {

        map.put(key, value);

    }

 

    public synchronized V get(K key) {

        return map.get(key);

    }

 

    public synchronized void remove(K key) {

        map.remove(key);

    }

 

    public synchronized Set> getAll() {

        return map.entrySet();

    }

 

    @Override

    public String toString() {

        StringBuilder stringBuilder = new StringBuilder();

        for (Map.Entry entry : map.entrySet()) {

            stringBuilder.append(String.format("%s: %s ", entry.getKey(), entry.getValue()));

        }

        return stringBuilder.toString();

    }

 

    public static void main(String[] args) {

        LRU1 lru1 = new LRU1<>(5);

        lru1.put(1, 1);

        lru1.put(2, 2);

        lru1.put(3, 3);

        System.out.println(lru1);

        lru1.get(1);

        System.out.println(lru1);

        lru1.put(4, 4);

        lru1.put(5, 5);

        lru1.put(6, 6);

        System.out.println(lru1);

    }

}

运行结果:

 

 

从运行结果中可以看出,实现了LRU缓存的思想。

 

接着使用HashMap和链表来实现LRU缓存。

 

主要的思想和上述基本一致,每次添加元素或者读取元素就将元素放置在链表的头,当缓存满了之后,就可以将尾结点元素删除,这样就实现了LRU缓存。

 

这种方法中是通过自己编写代码移动结点和删除结点,为了防止缓存大小超过限制,每次进行put的时候都会进行检查,若缓存满了则删除尾部元素。

 

import java.util.HashMap;

 

/**

 * 使用cache和链表实现缓存

 */

public class LRU2 {

    private final int MAX_CACHE_SIZE;

    private Entry head;

    private Entry tail;

 

    private HashMap> cache;

 

    public LRU2(int cacheSize) {

        MAX_CACHE_SIZE = cacheSize;

        cache = new HashMap<>();

    }

 

    public void put(K key, V value) {

        Entry entry = getEntry(key);

        if (entry == null) {

            if (cache.size() >= MAX_CACHE_SIZE) {

                cache.remove(tail.key);

                removeTail();

            }

            entry = new Entry<>();

            entry.key = key;

            entry.value = value;

            moveToHead(entry);

            cache.put(key, entry);

        } else {

            entry.value = value;

            moveToHead(entry);

        }

    }

 

    public V get(K key) {

        Entry entry = getEntry(key);

        if (entry == null) {

            return null;

        }

        moveToHead(entry);

        return entry.value;

    }

 

    public void remove(K key) {

        Entry entry = getEntry(key);

        if (entry != null) {

            if (entry == head) {

                Entry next = head.next;

                head.next = null;

                head = next;

                head.pre = null;

            } else if (entry == tail) {

                E

相关内容

热门资讯

杭州游之虎跑公园小学作文【经... 杭州游之虎跑公园小学作文 篇一我最喜欢的杭州景点之一就是虎跑公园。这个公园坐落在风景如画的西湖边,是...
“日”字变形记小学作文【推荐... “日”字变形记小学作文 篇一太阳的日子我喜欢太阳,因为它给了我们光明和温暖。太阳每天都会升起,照亮大...
小小的欲望作文350字(最新... 篇一:小小的欲望小小的欲望作文350字 篇一小小的欲望,是我们内心深处微不可见的火花,它时而燃烧得熊...
奇思妙想的作文400字(精选... 奇思妙想的作文400字 篇一标题:梦幻的花园我有一个奇妙的梦想,梦见自己拥有了一个令人惊叹的花园。这...
成长的烦恼四年级作文【优秀5... 成长的烦恼四年级作文 篇一成长的烦恼我是一名四年级的学生,正在经历着成长的烦恼。在成长的道路上,我遇...
爱人的作文【最新3篇】 爱人的作文 篇一爱人的作文我有一个特别重要的人,那就是我的爱人。他是我生命中最亲密的伴侣,也是我最深...
中秋之夜的小学作文500字 中秋之夜的小学作文500字  中秋节已悄悄的离我们近了,近了,此时我的心情又怎能不振奋呢?面临三天的...
有你真好的作文(最新6篇) 有你真好的作文 篇一爱与陪伴人生中,有太多的瞬间让我感受到了你的好。你是我最亲近的人,也是我最信任的...
火烧云小学作文【最新6篇】 火烧云小学作文篇一:火烧云的美丽火烧云是一种非常美丽的自然景观,它们在天空中绽放出绚丽的色彩,给人们...
人间自有温情在作文(精简3篇... 人间自有温情在作文 篇一温情的力量人间自有温情,在日常生活中,我们时常能够感受到这种力量。温情是指人...
小学三年级抗疫情作文(精简5... 小学三年级抗疫情作文 篇一:我们一起抗疫,共克时艰新冠疫情的突然爆发给全世界带来了巨大的挑战,人们的...
有你真好的作文(通用6篇) 有你真好的作文 篇一有你真好每个人的生活中都会有那么一个重要的人,他们的存在让我们的生活变得更加美好...
我上学了(优选3篇) 我上学了 篇一我上学了已经有好几年了,回想起来,这段时光仿佛就在眨眼间过去了。刚开始上学的时候,我还...
有趣的游戏小学作文400字【... 有趣的游戏小学作文400字 篇一标题:童年乐园——躲猫猫游戏在我心中,有一个让我欢乐无比的游戏,那就...
那次玩得真高兴作文(优秀5篇... 那次玩得真高兴作文 篇一那次玩得真高兴上个周末,我和我的朋友们一起去了游乐园玩,那次真是玩得太高兴了...
初一七年级学生作文题目【优选... 初一七年级学生作文题目 篇一我的暑假计划暑假即将来临,我对未来的两个月充满了期待和计划。今年的暑假,...
假如考上了名校,我要回来看看... 假如考上了名校,我要回来看看我的母校小学作文 篇一当我考上了名校,我内心感到无比的兴奋和自豪。这是我...
校园桂花香小学作文【最新3篇... 校园桂花香小学作文 篇一校园桂花香小学作文我所在的学校是一所名为桂花香小学的学校,这个名字来源于学校...
春天小学一年级作文300字(... 春天小学一年级作文300字 篇一春天的花儿春天是一个美丽的季节,大地万物都在春天苏醒,充满了生机和活...
小学中秋节的作文【优选3篇】 小学中秋节的作文 篇一中秋节是中国传统的节日之一,也是我最喜欢的节日。在这一天,我和家人一起庆祝,品...