package org.rx.cache;

import org.rx.common.*;
import org.rx.beans.DateTime; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Function; import static org.rx.common.Contract.as;
import static org.rx.common.Contract.require;
import static org.rx.util.AsyncTask.TaskFactory; public final class LRUCache<TK, TV> extends Disposable {
private class CacheItem {
public TV value;
private int expireSeconds;
private DateTime createTime;
private Consumer<TV> expireCallback; public CacheItem(TV value, int expireSeconds, Consumer<TV> expireCallback) {
this.value = value;
this.expireSeconds = expireSeconds;
this.expireCallback = expireCallback;
refresh();
} public void refresh() {
if (expireSeconds > -1) {
createTime = DateTime.utcNow();
}
} public void callback() {
if (expireCallback != null) {
expireCallback.accept(value);
}
}
} private static final Lazy<LRUCache<String, Object>> instance = new Lazy<>(() -> new LRUCache<>(1000, 120)); public static LRUCache<String, Object> getInstance() {
return instance.getValue();
} public static Object getOrStore(String key, Function<String, Object> supplier) {
require(key, supplier); return getInstance().getOrAdd(App.cacheKey(key), p -> supplier.apply(key));
} private final Map<TK, CacheItem> cache;
private int maxCapacity;
private int expireSeconds;
private Consumer<TV> expireCallback;
private Future future; public LRUCache(int maxSize, int expireSecondsAfterAccess) {
this(maxSize, expireSecondsAfterAccess, 8 * 1000, null);
} public LRUCache(int maxSize, int expireSecondsAfterAccess, long checkPeriod, Consumer<TV> removeCallback) {
cache = Collections.synchronizedMap(new LinkedHashMap<TK, CacheItem>(maxSize + 1, .75F, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<TK, CacheItem> eldest) {
boolean remove = size() > maxCapacity;
if (remove) {
eldest.getValue().callback();
}
return remove;
}
});
maxCapacity = maxSize;
expireSeconds = expireSecondsAfterAccess;
expireCallback = removeCallback;
future = TaskFactory.schedule(() -> {
for (Map.Entry<TK, CacheItem> entry : NQuery.of(cache.entrySet()).where(p -> p.getValue().expireSeconds > -1
&& DateTime.utcNow().addSeconds(-p.getValue().expireSeconds).after(p.getValue().createTime))) {
entry.getValue().callback();
cache.remove(entry.getKey());
}
}, checkPeriod);
} @Override
protected void freeObjects() {
if (future != null) {
future.cancel(true);
}
cache.clear();
} public void add(TK key, TV val) {
add(key, val, expireSeconds, expireCallback);
} public void add(TK key, TV val, int expireSecondsAfterAccess, Consumer<TV> removeCallback) {
require(key); cache.put(key, new CacheItem(val, expireSecondsAfterAccess, removeCallback));
} public void remove(TK key) {
remove(key, true);
} public void remove(TK key, boolean destroy) {
require(key);
CacheItem remove = cache.remove(key);
if (remove == null) {
return;
} AutoCloseable ac;
if (destroy && (ac = as(remove.value, AutoCloseable.class)) != null) {
try {
ac.close();
} catch (Exception ex) {
Logger.error(ex, "Auto close error");
}
}
} public TV get(TK key) {
require(key); CacheItem item = cache.get(key);
if (item == null) {
return null;
}
item.refresh();
return item.value;
} public TV getOrAdd(TK key, Function<TK, TV> supplier) {
require(key, supplier); CacheItem item = cache.get(key);
if (item == null) {
cache.put(key, item = new CacheItem(supplier.apply(key), expireSeconds, expireCallback));
} else {
item.refresh();
}
return item.value;
}
}

最新文章

  1. linux查看端口及端口详解
  2. Java IO设计模式彻底分析 (转载)
  3. PHP基础 创建
  4. ALinq Dynamic 使用指南——慨述(上)
  5. JVM学习笔记(二)------Java代码编译和执行的整个过程【转】
  6. 帝国cms相关调用
  7. UML中关系图解
  8. java RSA加密解密--转载
  9. JuliaSet&amp;MandelBulb @ Maya&amp;KK —— 4亿粒子的测试
  10. activebar的用法
  11. IOS设计模式--代理 (委托)
  12. 关于instrinsicContentSize, ContentHuggingPriority, ContentcompressionResistancePriority的理解
  13. UNIX网络编程——UDP编程模型
  14. Python3获取拉勾网招聘信息
  15. P3486 [POI2009]KON-Ticket Inspector
  16. excel怎么样批量将unix时间戳转化为北京时间
  17. 解决sqlserver修改被阻止的提示
  18. UE4里的自定义深度功能
  19. 铁乐学python_Day40_进程池
  20. jquery放大镜非常漂亮噢

热门文章

  1. 【笔记】Rancher2.1容器云平台新特性
  2. DAY 24继承与组合
  3. js 回文判断
  4. Charles手机抓包常见问题(各种常见坑)
  5. 20175317 《Java程序设计》第六周学习总结
  6. introduce explaining variable 引入解释变量
  7. 登录获取token,token参数关联至所有请求的请求体内
  8. Centos6与Centos7安装和使用htop
  9. git-commit Angular规范
  10. 【转】在Express项目中使用Handlebars模板引擎