zoukankan      html  css  js  c++  java
  • Java实现缓存(LRU,FIFO)

    吹吹牛逼,晒晒太阳。不如来写点东西,哈哈哈哈哈。。。。今天来说说,如何用java实现缓存,这个话题很多面试的也会被问到。今天就来说说。

    1.为什么要java实现缓存的?

    由于目前软件或网页的并发量增加很大,大量请求直接操作数据库,会对数据造成很大的压力。处理大量请求和连接时间会很长。而我们知道数据库中70%的数据是不需要修改的,那就可以引入缓存来进行读取,减少数据库的压力。

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

    缓存主要有LRU和FIFO,LRU是Least Recently Used的缩写,即最近最久未使用,FIFO就是先进先出,

    下面就使用Java来实现这两种缓存

    一。LRU缓存的思想

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

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

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

    按照上面的思想我们可以使用LikedHashMap来实现LRU缓存

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

    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

    由于LinkedHashMap是为自动扩容的,当table数组中元素大于Capacity * loadFactor的时候,就会自动进行两倍扩容。但是为了使缓存大小固定,就需要在初始化的时候传入容量大小和负载因子。
    为了使得到达设置缓存大小不会进行自动扩容,需要将初始化的大小进行计算再传入,可以将初始化大小设置为(缓存大小 / loadFactor) + 1,这样就可以在元素数目达到缓存大小时,也不会进行扩容了。这样就解决了上述第一点问题。


    代码实现
    package com.huojg.test.Test;
    
    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.Set;
    
    public class LRUCache<K, V> {
        private final int MAX_CACHE_SIZE;
        private final float DEFAULT_LOAD_FACTORY = 0.75f;
    
        LinkedHashMap<K, V> map;
    
        public LRUCache(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<K, V>(capacity, DEFAULT_LOAD_FACTORY, true) {
                @Override
                protected boolean removeEldestEntry(Map.Entry<K, V> 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<Map.Entry<K, V>> getAll() {
            return map.entrySet();
        }
    
        @Override
        public String toString() {
            StringBuilder stringBuilder = new StringBuilder();
            for (Map.Entry<K, V> entry : map.entrySet()) {
                stringBuilder.append(String.format("%s: %s  ", entry.getKey(), entry.getValue()));
            }
            return stringBuilder.toString();
        }
    
        public static void main(String[] args) {
            LRUCache<Integer, Integer> lru1 = new LRUCache<>(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);
        }
    }

    结果输出:

    1: 1  2: 2  3: 3  
    2: 2  3: 3  1: 1  
    3: 3  1: 1  4: 4  5: 5  6: 6  

    实现了LRU缓存的思想

    FIFO

    FIFO就是先进先出,可以使用LinkedHashMap进行实现。
    当第三个参数传入为false或者是默认的时候,就可以实现按插入顺序排序,就可以实现FIFO缓存了。

    实现代码跟上述使用LinkedHashMap实现LRU的代码基本一致,主要就是构造函数的传值有些不同。

    package com.huojg.test.Test;
    
    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.Set;
    
    public class FIFOCache<K, V> {
        private final int MAX_CACHE_SIZE;
        private final float DEFAULT_LOAD_FACTORY = 0.75f;
    
        LinkedHashMap<K, V> map;
    
        public FIFOCache(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<K, V>(capacity, DEFAULT_LOAD_FACTORY, false) {
                @Override
                protected boolean removeEldestEntry(Map.Entry<K, V> 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<Map.Entry<K, V>> getAll() {
            return map.entrySet();
        }
    
        @Override
        public String toString() {
            StringBuilder stringBuilder = new StringBuilder();
            for (Map.Entry<K, V> entry : map.entrySet()) {
                stringBuilder.append(String.format("%s: %s  ", entry.getKey(), entry.getValue()));
            }
            return stringBuilder.toString();
        }
    
        public static void main(String[] args) {
            FIFOCache<Integer, Integer> lru1 = new FIFOCache<>(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);
        }
    }

    结果输出

    1: 1  2: 2  3: 3  
    1: 1  2: 2  3: 3  
    2: 2  3: 3  4: 4  5: 5  6: 6  

    以上就是使用Java实现这两种缓存的方式,从中可以看出,LinkedHashMap实现缓存较为容易,因为底层函数对此已经有了支持,自己编写链表实现LRU缓存也是借鉴了LinkedHashMap中实现的思想。在Java中不只是这两种数据结构可以实现缓存,比如ConcurrentHashMap、WeakHashMap在某些场景下也是可以作为缓存的,到底用哪一种数据结构主要是看场景再进行选择,但是很多思想都是可以通用的。






  • 相关阅读:
    RecyclerView 数据刷新的几种方式 局部刷新 notify MD
    【图片】批量获取几万张图片
    RV BaseRecyclerViewAdapterHelper 总结 MD
    RecyclerView.ItemDecoration 间隔线
    Kotlin【简介】Android开发 配置 扩展
    Kotlin 特性 语法糖 优势 扩展 高阶 MD
    一个十分简洁实用的MD风格的UI主框架
    折叠伸缩工具栏 CollapsingToolbarLayout
    FloatingActionButton FAB 悬浮按钮
    Glide Picasso Fresco UIL 图片框架 缓存 MD
  • 原文地址:https://www.cnblogs.com/huojg-21442/p/7286315.html
Copyright © 2011-2022 走看看