自己实现一个有限队列缓存【有大小和存活时间限制】
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
在日常工作中,我们可能会用到队列缓存数据,缓存的时间存活时间有限制,那么JDK自带的HashMap并不能满足我们的需求,那我们就自己来实现一个。
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 基于LinkedHashMap实现的一个有限队列缓存 有时间及大小的限制
* aliveTime参数为true时为模拟lru规则
*
* @author lijilin
* @version 1.0
* @description: TODO
* @date 2022/1/19 11:00
*/
public class LimitedCacheMap<K, V>
{
private final LinkedHashMap<K, Element<V>> data;
/**
* 缓存最大容量,添加新元素时,若当前长度超过容量,则会删除队首元素
*/
private final int capacity;
/**
* 生存的时长 毫秒
*/
private final long aliveTime;
/**
* 是否使用lru规则,为true时表示当元素被查找命中时被重放到队尾
*/
private final boolean useLru;
/**
* 读写锁
*/
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
private final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
public LimitedCacheMap(int capacity, long aliveTime)
{
this(capacity, aliveTime, Boolean.FALSE);
}
public LimitedCacheMap(int capacity, long aliveTime, boolean useLru)
{
this.capacity = capacity;
this.aliveTime = aliveTime;
this.useLru = useLru;
this.data = new LinkedHashMap<K, Element<V>>(capacity, 1.0f, useLru)
{
private static final long serialVersionUID = 1L;
@Override
protected boolean removeEldestEntry(Map.Entry<K, Element<V>> eldest)
{
if (size() > capacity)
{
return true;
}
long eleAliveTime = System.currentTimeMillis() - eldest.getValue().bornTime;
return (eleAliveTime > aliveTime);
}
};
}
public V put(K key, V value)
{
V preValue = null;
Element<V> newValue = new Element<>(value);
readLock.lock();
try
{
if (data.containsKey(key))
{
preValue = data.get(key).value;
}
data.put(key, newValue);
return preValue;
} finally
{
readLock.unlock();
}
}
/**
* 获取数据
*/
public V get(K key)
{
// 当使用lru,元素重放回队尾涉及到写操作,所以用写锁
Lock lock = this.useLru ? this.writeLock : this.readLock;
Element<V> target;
lock.lock();
try
{
target = this.data.get(key);
if (target == null)
{
return null;
}
} finally
{
lock.unlock();
}
long eleAliveTime = System.currentTimeMillis() - target.bornTime;
if (eleAliveTime < aliveTime)
{
return target.value;
}
remove(key);
return null;
}
/**
* 获取size
*
* @return
*/
public int size()
{
this.readLock.lock();
try
{
return this.data.size();
} finally
{
this.readLock.unlock();
}
}
/**
* 清空数据
*/
public void clear()
{
this.writeLock.lock();
try
{
this.data.clear();
} finally
{
this.writeLock.unlock();
}
}
/**
* 删除指定元素
*/
private void remove(K key)
{
this.writeLock.lock();
try
{
this.data.remove(key);
} finally
{
this.writeLock.unlock();
}
}
static class Element<V>
{
V value;
/**
* 元素添加时的时间戳
*/
long bornTime;
public Element(V value)
{
this.value = value;
this.bornTime = System.currentTimeMillis();
}
@Override
public String toString()
{
return "Element{" +
"value=" + value +
", bornTime=" + bornTime +
'}';
}
}
@Override
public String toString()
{
return "LimitedCacheMap{" +
"data=" + data +
", capacity=" + capacity +
", aliveTime=" + aliveTime +
", useLru=" + useLru +
", lock=" + lock +
", readLock=" + readLock +
", writeLock=" + writeLock +
'}';
}
public static void main(String[] args) throws InterruptedException
{
LimitedCacheMap<Integer, Integer> map = new LimitedCacheMap<>(3, 1500);
map.put(1, 1);
map.put(2, 1);
map.put(3, 1);
map.put(4, 1);
map.put(5, 1);
map.put(7, 1);
System.out.println(map);
}
}