这里仅仅为了备忘所用
缓存更新接口
package com.littlehow.cache;
/**
* 缓存获取的调用接口
* @author littlehow
* @date 2019/1/22
* @param <K>
* @param <V>
*/
public interface Call<K, V> {
/**
* 获取缓存信息
* @param k
* @return -- 对应的缓存信息
*/
V get(K k);
}
缓存实现类
package com.littlehow.cache;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
/**
* java内存缓存,淘汰策略为LRU简版,将最长时间不使用的缓存淘汰
* @author littlehow
* @date 2019/1/22
* @param <K>
* @param <V>
*/
public class JavaCache<K, V> {
/* 最大缓存容量 */
private final int maxSize;
/* 缓存有效时间, -1为永久有效,毫秒数 */
private final long validTime;
/* 总调用次数 */
public final AtomicLong totalCount = new AtomicLong();
/* 缓存总命中次数 */
public final AtomicLong hitCount = new AtomicLong();
/* 缓存信息 */
private final ConcurrentHashMap<Node, V> cache = new ConcurrentHashMap<>();
/* key对应的映射信息 */
private final ConcurrentHashMap<K, Node> keyMapping = new ConcurrentHashMap<>();
/* 缓存加载类 */
private final Call<K, V> call;
/* 头节点 */
private volatile Node head;
/* 尾节点 */
private volatile Node tail;
private JavaCache(int maxSize, Call call, long validTime) {
this.maxSize = maxSize;
this.call = call;
this.validTime = validTime;
}
public static <K, V> JavaCache newCache(int maxSize, Call<K, V> call) {
return new JavaCache(maxSize, call, -1);
}
/**
* 设置有效时间的缓存类
* @param maxSize
* @param call
* @param validTime
* @param <K>
* @param <V>
* @return
*/
public static <K, V> JavaCache newCache(int maxSize, Call<K, V> call, long validTime) {
return new JavaCache(maxSize, call, validTime);
}
/**
* 链表
*/
private final class Node {
volatile Node prev;
volatile Node next;
final K key;
//保持最后可用时间的可见
volatile long lastUseTime;
Node(K key) {
this.key = key;
}
@Override
public int hashCode() {
return key.hashCode();
}
@Override
public boolean equals(Object o) {
return key.equals(o);
}
@Override
public String toString() {
return key.toString();
}
}
/**
* 获取缓存信息
* @param k -- 对应的缓存key
* @return
*/
public V get(K k) {
totalCount.getAndIncrement();
V v = null;
Node key = keyMapping.get(k);
if (isValidKey(key)) {
hitCount.getAndIncrement();
//获取缓存值
v = cache.get(key);
updateKey(key);
} else {
if (key == null) {
key = new Node(k);
}
v = loadValue(key);
}
return v;
}
private synchronized V loadValue(Node key) {
V v;
if (keyMapping.containsKey(key.key) && isValidKey(key)) {
hitCount.getAndIncrement();
updateKey(key);
v = cache.get(key);
} else {
v = call.get(key.key);
//判断是否已经饱和
if (v != null) {
if (isFull()) {
//清除最后使用的
Node tmp = tail;
keyMapping.remove(tmp.key);
cache.remove(tmp);
tail = tmp.prev;
}
updateKey(key);
keyMapping.put(key.key, key);
cache.put(key, v);
}
}
return v;
}
private boolean isFull() {
return keyMapping.size() > maxSize;
}
/**
* 更新节点key,如果需要设置头尾,则设置
* @param key
*/
private synchronized void updateKey(Node key) {
if (validTime != -1) {//因为对volatile的写有性能损耗,所以如果缓存永久不过期,则不写最后使用时间
key.lastUseTime = System.currentTimeMillis();
}
if (tail == null) {//第一次
tail = head = key;
} else if (key == tail && key != head) {
tail = key.prev;
tail.next = null;
}
if (key != head) {
key.next = head;
head.prev = key;
head = key;
key.prev = null;
}
}
private boolean isValidKey(Node node) {
long currentTime = System.currentTimeMillis();
return node != null && (validTime == -1 || (currentTime - node.lastUseTime < validTime));
}
}