返回顶部

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

 

 

 

posted @ 2018-11-07 01:46  jaden好青年  阅读(269)  评论(0编辑  收藏  举报