zoukankan      html  css  js  c++  java
  • LRUCache

    请简述LRUcache原理,及常见应用场景。使用常用的java数据结构实现。

    LRU(Least Recently Used)缓存算法是近期最少使用算法,其核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。主要算法原理是把最近使用的对象强引用存储在LinkedHashMap中,当缓存满时,把最近最少使用的对象从内存中移除,并提供了get和put方法来完成缓存的获取和添加操作。

    1、LRU的LinkedHashMap同步锁实现

    package com.boomoom.service.localDataMap
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    public class LRUCache<K, V> {
        private static final float hashLoadFactory = 0.75f;
        private LinkedHashMap<K, V> map;
        private int cacheSize;
    
        public LRUCache(int cacheSize) {
         this.cacheSize = cacheSize;
            int capacity = (int)Math.ceil(cacheSize / hashLoadFactory) + 1;
            map = new LinkedHashMap<K, V>(capacity, hashLoadFactory, true) {
                private static final long serialVersionID = 1;
    
                @Override
                protected boolean removeEldestEntry(Map.Entry eldest) {
                    return size() > LRUCache.this.cacheSize;
                }
            };
        }
    
        public V get(K key) {
            synchronized(this) {
                return map.get(key);
            }
        }
    
        public void put(K key, V value) {
            synchronized(this) {
                map.put(key, value);
            }
        }
    
        public void remove(Object key) {
            synchronized(this) {
                map.remove(key);
            }
        }
    
        public void clear() {
            synchronized(this) {
                map.clear();
            }
        }
    }

    2、LRU的LinkedHashMap读写锁实现

    package com.boomoom.service.localDataMap
    import java.util.LinkedHashMap;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class LruCache<K, V> {
        private int MAX_LENGTH = 1 << 30;  //最大长度
        private LinkedHashMap<K, V> map;
        private ReadWriteLock lock = new ReentrantReadWriteLock(); //读写锁
    
        public LruCache(int initLength) {
            this(initLength, MAX_LENGTH);
        }
    
        public LruCache(int initLength, int maxLength) {
            MAX_LENGTH = maxLength;
            map = new LinkedHashMap<K, V>(initLength, 0.75f, true) {
                @Override
                protected boolean removeEldestEntry(Entry<K, V> eldest) {
                    return size() > MAX_LENGTH;
                }
            };
        }
    
        /**
         * 添加项
         *
         * @param item  项
         * @param state 状态
         */
        public void put(K item, V state) {
            lock.writeLock().lock();
            map.put(item, state);
            lock.writeLock().unlock();
        }
    
        /**
         * 获取值,使用前请判断是否存在item
         *
         * @param item 项
         * @return value 值
         */
        public V get(String item) {
            lock.readLock().lock();
            V value = map.get(item);
            lock.readLock().unlock();
            return value;
        }
    
        /**
         * 是否存在
         *
         * @param item 项
         * @return 是否存在
         */
        public boolean containsKey(String item) {
            lock.readLock().lock();
            boolean isContainer = map.containsKey(item);
            lock.readLock().unlock();
            return isContainer;
        }
    
        /**
         * 删除item
         *
         * @param item 项
         */
        public void remove(String item) {
            lock.writeLock().lock();
            map.remove(item);
            lock.writeLock().unlock();
        }
    }

    synchronized和ReadWriteLock的区别在于:

    ReadWriteLock读写锁,当读取的时候线程会获得read锁,其他线程也可以获得read锁同时并发的去读取,但是写程序运行获取到write锁的时候,其他线程是不能进行操作的,因为write是排它锁,而synchronized不管你是read还是write没有抢到锁的线程都会被阻塞。

    3、LRUCache的hashMap实现

    需要注意的是,这段不是线程安全的,要想做到线程安全,同上两例需要加上synchronized等。

    public class LRUCache<K, V> {
    
        private Node head;
        private Node end;
        //缓存存储上限
        private int  limit;
    
        private HashMap<String, Node> hashMap;
    
        public LRUCache(int limit) {
            this.limit = limit;
            hashMap = new HashMap<String, Node>();
        }
    
        public String get(String key) {
            Node node = hashMap.get(key);
            if (node == null) {
                return null;
            }
            refreshNode(node);
            return node.value;
        }
    
        public void put(String key, String value) {
            Node node = hashMap.get(key);
            if (node == null) {
                //如果key不存在,插入key-value
                if (hashMap.size() >= limit) {
                    String oldKey = removeNode(head);
                    hashMap.remove(oldKey);
                }
                node = new Node(key, value);
                addNode(node);
                hashMap.put(key, node);
            } else {
                //如果key存在,刷新key-value
                node.value = value;
                refreshNode(node);
            }
        }
    
        public void remove(String key) {
            Node node = hashMap.get(key);
            removeNode(node);
            hashMap.remove(key);
        }
    
        /**
         * 刷新被访问的节点位置
         *
         * @param node 被访问的节点
         */
    
        private void refreshNode(Node node) {
            //如果访问的是尾节点,无需移动节点
            if (node == end) {
                return;
            }
            //移除节点
            removeNode(node);
            //重新插入节点
            addNode(node);
        }
    
        /**
         * 删除节点
         *
         * @param node 要删除的节点
         */
    
        private String removeNode(Node node) {
            if (node == end) {
                //移除尾节点
                end = end.pre;
            } else if (node == head) {
                //移除头节点
                head = head.next;
            } else {
                //移除中间节点
                node.pre.next = node.next;
                node.next.pre = node.pre;
            }
            return node.key;
        }
    
        /**
         * 尾部插入节点
         *
         * @param node 要插入的节点
         */
    
        private void addNode(Node node) {
            if (end != null) {
                end.next = node;
                node.pre = end;
                node.next = null;
            }
            end = node;
            if (head == null) {
                head = node;
            }
        }
    
        class Node {
            Node(String key, String value) {
                this.key = key;
                this.value = value;
            }
    
            public Node   pre;
            public Node   next;
            public String key;
            public String value;
        }
    
        public static void main(String[] args) {
            LRUCache lruCache = new LRUCache(5);
            lruCache.put("001", "用户1信息");
            lruCache.put("002", "用户1信息");
            lruCache.put("003", "用户1信息");
            lruCache.put("004", "用户1信息");
            lruCache.put("005", "用户1信息");
            lruCache.get("002");
            lruCache.put("004", "用户2信息更新");
            lruCache.put("006", "用户6信息");
            System.out.println(lruCache.get("001"));
            System.out.println(lruCache.get("006"));
        }
    }
    LRUCache

  • 相关阅读:
    双camera景深计算
    解决单反出片发灰难题 教你让照片变得通透
    增强画面纵深感的几个小技巧
    双目视觉算法简介
    Android系统源代码的下载与编译
    android 7.0 (nougat)的编译优化-ninja
    神奇的图像处理算法
    【老戴说镜头】浅谈双摄镜头技术
    [Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现
    关于DLL模块导出函数
  • 原文地址:https://www.cnblogs.com/boomoom/p/9919973.html
Copyright © 2011-2022 走看看