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")); } }