手写一个LruCache
Posted 这个需求做不了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写一个LruCache相关的知识,希望对你有一定的参考价值。
代码实现一 (直接继承ListHashMap.java)
package org.java.write.lru;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
private final int maxCapacity;
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
private final Lock lock = new ReentrantLock();
public LRULinkedHashMap(int maxCapacity) {
super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
this.maxCapacity = maxCapacity;
}
//重新removeEldestEntry 方法 当前size大于maxCapacity时 删除最老的数据
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxCapacity;
}
@Override
public boolean containsKey(Object key) {
try {
lock.lock();
return super.containsKey(key);
} finally {
lock.unlock();
}
}
@Override
public V get(Object key) {
try {
lock.lock();
;
return super.get(key);
} finally {
lock.unlock();
}
}
@Override
public V put(K key, V value) {
try {
lock.lock();
return super.put(key, value);
} finally {
lock.unlock();
}
}
@Override
public int size() {
try {
lock.lock();
return super.size();
} finally {
lock.unlock();
}
}
@Override
public void clear() {
try {
lock.lock();
super.clear();
} finally {
lock.unlock();
}
}
public Collection<Map.Entry<K, V>> getAll() {
try {
lock.lock();
return new ArrayList<Map.Entry<K, V>>(super.entrySet());
} finally {
lock.unlock();
}
}
}
代码实现二
package org.java.write.lru;
import java.util.HashMap;
import java.util.LinkedList;
public class LruCache<K, V> {
private int currentCacheSize;
private int cacheCapacity;
private HashMap<K, CacheNode<K, V>> caches;
private CacheNode<K, V> first;
private CacheNode<K, V> last;
public LruCache(int size) {
currentCacheSize = 0;
this.cacheCapacity = size;
caches = new HashMap<K, CacheNode<K, V>>(size);
}
public void put(K k, V v) {
CacheNode<K, V> node = caches.get(k);
//等于null 则代表缓存里没有数据 需要进行缓存
if (node == null) {
//如果超出范围 超出需要移除最后一个
if (caches.size() >= cacheCapacity) {
caches.remove(last.key);
removeLast();
}
}
//构建cacheNode 新构建的节点 应该是
node = new CacheNode<K, V>();
node.key = k;
node.value = v;
moveToFirst(node);
caches.put(k, node);
currentCacheSize++;
}
public V get(K k) {
CacheNode<K, V> node = caches.get(k);
if (node == null) {
return null;
}
//将当前node 移动到首位
moveToFirst(node);
return node.value;
}
public V remove(K k) {
CacheNode<K, V> node = caches.get(k);
if (node != null) {
//获取当前删除节点的前置节点,如果不为空 把前置节点的下一节点 置为当前删除节点的下一节点 (链表重新链接)
if (node.pre != null) {
node.pre.next = node.next;
}
//获取当前删除节点的后置节点,如果不为空 把后置节点的前置节点 置位当前删除节点的上一节点(链表重新连接)
if (node.next != null) {
node.next.pre = node.pre;
}
//判断当前删除节点是否是首节点 是的话 首节点需要变更 需要变更为当前删除节点的下一节点
if (node == first) {
first = node.next;
}
//判断当前删除
if (node == last) {
last = node.pre;
}
currentCacheSize--;
}
return caches.remove(k).value;
}
public void clear() {
first = null;
last = null;
currentCacheSize = 0;
cacheCapacity = 0;
caches.clear();
}
private void moveToFirst(CacheNode<K, V> node) {
//判断当前节点是否是首节点 初始化的时候 first 是null
if (first == node) {
return;
}
//自行想一下链表的结构
if (node.next != null) {
node.next.pre = node.pre;
}
//自行想一下链表的结构
if (node.pre != null) {
node.pre.next = node.next;
}
//如果节点是尾节点,
if (node == last) {
last = last.pre;
}
//如果first 节点和last节点都是空的 代表是缓存的第一个数据 需要将该节点设置为首节点和尾节点
if (first == null || last == null) {
first = last = node;
return;
}
node.next = first;
first.pre = node;
first = node;
first.pre = null;
}
/**
* 移除最后一个元素
*/
private void removeLast() {
//最后一个元素是否为空
if (last != null) {
last = last.pre;
if (last == null) {
first = null;
} else {
last.next = null;
}
}
currentCacheSize--;
}
static class CacheNode<K, V> {
CacheNode<K, V> pre;
CacheNode<K, V> next;
K key;
V value;
public CacheNode() {
}
}
}
代码github write-lru-cache 分支
以上是关于手写一个LruCache的主要内容,如果未能解决你的问题,请参考以下文章
redis前传自己手写一个LRU策略 | redis淘汰策略
redis前传自己手写一个LRU策略 | redis淘汰策略