這裏僅僅爲了備忘所用
緩存更新接口
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));
}
}