美文网首页
JAVA高级(6)—— LinkedHashMap

JAVA高级(6)—— LinkedHashMap

作者: AndroidMaster | 来源:发表于2018-01-01 10:51 被阅读46次

    概述

    • 通过维护一个双向链表,LinkedHashMap保证了元素迭代的顺序。
    • 可以认为是HashMap+LinkedList,即它既使用HashMap操作数据结构,又使用LinkedList维护插入元素的先后顺序

    实现LRU算法缓存

    1、LRU:Least Recently Used,最近最少使用,也就是说,当缓存满了,会优先淘汰那些最近最不常访问的数据
    2、boolean型参数的构造方法:LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder)
    就是这个accessOrder,它表示:

    false,所有的Entry按照插入的顺序排列
    true,所有的Entry按照访问的顺序排列

    意思就是,如果有1 2 3这3个Entry,那么访问了1,就把1移到尾部去,即2 3 1。每次访问都把访问的那个数据移到双向队列的尾部去,那么每次要淘汰数据的时候,双向队列最头的那个数据不就是最不常访问的那个数据了吗?换句话说,双向链表最头的那个数据就是要淘汰的数据。
    "访问",这个词有两层意思:

    根据Key拿到Value,也就是get方法
    修改Key对应的Value,也就是put方法

    还有一个判断是否删除最老数据的方法,默认是返回false,即不删除数据,我们使用LinkedHashMap实现LRU缓存的方法就是对LinkedHashMap实现简单的扩展,扩展方式有两种,一种是inheritance,一种是delegation

    //LinkedHashMap自带的判断是否删除最老的元素方法,默认返回false,即不删除老数据
    //我们要做的就是重写这个方法,当满足一定条件时删除老数据
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
            return false;
    }
    

    LRU缓存LinkedHashMap(inheritance)实现

    采用inheritance方式实现比较简单,而且实现了Map接口,在多线程环境使用时可以使用 Collections.synchronizedMap()方法实现线程安全操作

    public class LRUCache2<K, V> extends LinkedHashMap<K, V> {
        private final int MAX_CACHE_SIZE;
    
        public LRUCache2(int cacheSize) {
            super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
            MAX_CACHE_SIZE = cacheSize;
        }
    
        @Override
        protected boolean removeEldestEntry(Map.Entry eldest) {
            return size() > MAX_CACHE_SIZE;
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<K, V> entry : entrySet()) {
                sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
            }
            return sb.toString();
        }
    }
    

    这样算是比较标准的实现吧,实际使用中这样写还是有些繁琐,更实用的方法时像下面这样写,省去了单独建一个类的麻烦

    final int cacheSize = 100;
    Map<String, String> map = new LinkedHashMap<String, String>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
        return size() > cacheSize;
        }
    };
    

    LRU缓存LinkedHashMap(delegation)实现

    delegation方式实现更加优雅一些,但是由于没有实现Map接口,所以线程同步就需要自己搞定了

    public class LRUCache3<K, V> {
    
        private final int MAX_CACHE_SIZE;
        private final float DEFAULT_LOAD_FACTOR = 0.75f;
        LinkedHashMap<K, V> map;
    
        public LRUCache3(int cacheSize) {
            MAX_CACHE_SIZE = cacheSize;
            //根据cacheSize和加载因子计算hashmap的capactiy,+1确保当达到cacheSize上限时不会触发hashmap的扩容,
            int capacity = (int) Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTOR) + 1;
            map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTOR, 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<Map.Entry<K, V>> getAll() {
            return map.entrySet();
        }
    
        public synchronized int size() {
            return map.size();
        }
    
        public synchronized void clear() {
            map.clear();
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            for (Map.Entry entry : map.entrySet()) {
                sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
            }
            return sb.toString();
        }
    }
    

    参考文献

    图解集合6:LinkedHashMap
    LRU缓存实现(Java)

    相关文章

      网友评论

          本文标题:JAVA高级(6)—— LinkedHashMap

          本文链接:https://www.haomeiwen.com/subject/fqxtnxtx.html