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;
}
}

java LRUCache的更多相关文章

  1. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  2. Java HashMap的死循环 以及 LRUCache的正确实现

    今天RP爆发,16核服务器load飙到30多,cpu使用情况全部99%以上. 从jstack中分析发现全部线程都堵在map.transfer处,如下: "pool-10-thread-23& ...

  3. 一个最简单的LRUCache实现 (JAVA)

    流程图: 1. 代码 import java.util.ArrayList; public class LRUCache { private int cacheMaxSize = 0; private ...

  4. java LinkedHashMap实现LRUCache缓存

    package java_map; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map ...

  5. Java容器解析系列(17) LruCache详解

    在之前讲LinkedHashMap的时候,我们说起可以用来实现LRU(least recent used)算法,接下来我看一下其中的一个具体实现-----android sdk 中的LruCache. ...

  6. Java集合之LinkedHashMap

    一.初识LinkedHashMap 上篇文章讲了HashMap.HashMap是一种非常常见.非常有用的集合,但在多线程情况下使用不当会有线程安全问题. 大多数情况下,只要不涉及线程安全问题,Map基 ...

  7. LruCache算法原理及实现

    LruCache算法原理及实现 LruCache算法原理 LRU为Least Recently Used的缩写,意思也就是近期最少使用算法.LruCache将LinkedHashMap的顺序设置为LR ...

  8. Java 对象引用方式 —— 强引用、软引用、弱引用和虚引用

    Java中负责内存回收的是JVM.通过JVM回收内存,我们不需要像使用C语音开发那样操心内存的使用,但是正因为不用操心内存的时候,也会导致在内存回收方面存在不够灵活的问题.为了解决内存操作不灵活的问题 ...

  9. LruCache为GridView异步加载大量网络图片

    MainActivity如下: import android.os.Bundle; import android.widget.GridView; import android.app.Activit ...

随机推荐

  1. [原][译]我们为什么需要另一个c++测试框架?Catch||Why do we need yet another C++ test framework?

    翻译问题来源:https://github.com/catchorg/Catch2/blob/master/docs/why-catch.md 其他辅助博文:从Google Test 转到 Catch ...

  2. Kafka知识总结

    1.kafka是什么 类JMS消息队列,结合JMS中的两种模式,可以有多个消费者主动拉取数据,在JMS中只有点对点模式才有消费者主动拉取数据. kafka是一个生产-消费模型. Producer:生产 ...

  3. springboot缓存注解——@CacheEvict

    @CacheEvict:缓存清除 可以通过key指定清除的数据 如果不写默认参数的值 allEntries = true (是否删除该缓存名中所有数据,默认为false) beforeInvocati ...

  4. 项目部署Vue+Django(luffy)

    部署路飞学城 部署整体框架图: 1 熟悉linux操作 2 上传路飞学城项目到linux服务器 xftp上传到服务器 lrzsz工具 3 完成python3解释器的安装 在linux命令行模式下, 输 ...

  5. IDEA外部工具配置-OpenJML篇

    帮助文档 jetbrains帮助文档:https://www.jetbrains.com/help/idea/settings-tools-external-tools.html 使用external ...

  6. ASP.NET 发送邮件 SMTP

    目录 // 邮件信息 对象                MailMessage mail = new MailMessage(); //新建邮件SMTP客户端   对象          用于发送 ...

  7. 5、继承(extends)

    继承主要目的是提高代码的复用性,但是只有在类与类之间有所属关系的时候才能继承,不能为了获取其他类的功能而继承,Java中只有单继承,不支持多继承,但可以多层继承 当父类中定义了相同的功能,内容不同时, ...

  8. ES5 & ES6 基础

    一.什么是ES5 附上一览表 (5.1中文 (2011.6)): http://lzw.me/pages/ecmascript/ (5.1英文PDF):http://www.ecma-internat ...

  9. Intellij IDEA 自动清除无效 import

    打开偏好设置: 输入auto import: 注:想在以后的工程中都自动清除,可以在File中如下图操作:

  10. 两年前详细分析了ijkplayer的代码

    两年前详细分析了ijkplayer的代码,太久没总结了,现在只能上传一张图片了.把fly替换成ijk就行了. 用diagramDesigner画的,因为这个工具足够简单,用visio不知道要画到什么时 ...