背景:设计一个缓存,如果在N秒内访问了M次,则为热点数据,针对热点数据,直接去访问缓存,否则去访问数据库。
设计:利用一个Map<String,Node>hotMap去维护热点的key。
其中Node的设计为:
其中arr为当前缓存的一个数组,用于记录访问次数
preQuery 记录上一次访问时间
preIndex记录上一次的index。
static class Node {
int[] arr;
long preQuery;
int preIndex;
Node(int size) {
arr = new int[size];
}
}
接口设计:
public interface SmartCache {
String get(String key);
}
实现:
public class SmartCacheImpl implements SmartCache {
private static final int N = 6;
private static final int M = 5;
private static final Map<String, Node> hotMap = new ConcurrentHashMap<>();
private static final Map<String, String> cache = new ConcurrentHashMap<>();
public static void main(String[] args) throws InterruptedException {
SmartCache smartCache = new SmartCacheImpl();
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
smartCache.get("xy-1");
System.out.println("-------------------------------------");
}
Thread.sleep(4100);
smartCache.get("xy-1");
}
@Override
public String get(String key) {
if (isHot(key)) {
System.out.println("热点key,从缓存中获取");
Arrays.stream(hotMap.get(key).arr).forEach(e -> System.out.print(e + " "));
return cache.get(key);
}
String value = getFromDB(key);
cache.put(key, value);
Arrays.stream(hotMap.get(key).arr).forEach(e -> System.out.print(e + " "));
return value;
}
private String getFromDB(String key) {
System.out.println("从数据库中去取:" + key);
return "从数据库中去取:" + key;
}
private boolean isHot(String key) {
long nao = System.currentTimeMillis() / 1000;
System.out.println("当前访问tick:" + nao);
int index = (int) (nao % N);
if (hotMap.containsKey(key)) {
Node node = hotMap.get(key);
if (nao - node.preQuery >= N) {
node.arr = new int[N + 1];
node.arr[index] = 1;
node.preQuery = nao;
node.preIndex = index;
System.out.println(N + "秒内无访问重置");
return false;
}
node.arr[index] = node.arr[node.preIndex] + 1;
for (int i = node.preIndex; i < index; i++) {
node.arr[i] = node.arr[index];
}
node.arr[N] = node.arr[0];
System.out.println("当前访问index:" + index + " 次数:" + (node.arr[index] - node.arr[index + 1]));
if (node.arr[index] - node.arr[index + 1] > M) {
node.preQuery = nao;
node.preIndex = index;
return true;
}
node.preQuery = nao;
node.preIndex = index;
} else {
Node node = new Node(N + 1);
node.arr[index] = 1;
node.preQuery = nao;
node.preIndex = index;
hotMap.put(key, node);
}
return false;
}
static class Node {
int[] arr;
long preQuery;
int preIndex;
Node(int size) {
arr = new int[size];
}
}
}