java实现带过期时间的缓存
private static ScheduledExecutorService swapExpiredPool
= new ScheduledThreadPoolExecutor(10); private ReentrantLock lock = new ReentrantLock(); private ConcurrentHashMap<String, Node> cache = new ConcurrentHashMap<>(1024);
/**
* 让过期时间最小的数据排在队列前,在清除过期数据时
* ,只需查看缓存最近的过期数据,而不用扫描全部缓存
*
* @see Node#compareTo(Node)
* @see SwapExpiredNodeWork#run()
*/
private PriorityQueue<Node> expireQueue = new PriorityQueue<>(1024); public LocalCache() { //使用默认的线程池,每5秒清除一次过期数据
//线程池和调用频率 最好是交给调用者去设置。
swapExpiredPool.scheduleWithFixedDelay(
new SwapExpiredNodeWork(), 5, 5, TimeUnit.SECONDS);
} public Object set(String key, Object value, long ttl) { Assert.isTrue(StringUtils.hasLength(key), "key can't be empty");
Assert.isTrue(ttl > 0, "ttl must greater than 0"); long expireTime = System.currentTimeMillis() + ttl;
Node newNode = new Node(key, value, expireTime);
lock.lock();
try {
Node old = cache.put(key, newNode);
expireQueue.add(newNode);
//如果该key存在数据,还要从过期时间队列删除
if (old != null) {
expireQueue.remove(old);
return old.value;
}
return null;
} finally {
lock.unlock();
} } /**
* 拿到的数据可能是已经过期的数据,可以再次判断一下
* if(n.expireTime<System.currentTimeMillis()){
* return null;
* }
* 也可以直接返回整个节点Node ,交给调用者去取舍
* <p>
* <p>
* 无法判断不存在该key,还是该key存的是一个null值,如果需要区分这两种情况
* 可以定义一个全局标识,标识key不存在
* public static final NOT_EXIST = new Object();
* 返回值时
* return n==null?NOT_EXIST:n.value;
*/
public Object get(String key) {
Node n = cache.get(key);
return n == null ? null : n.value;
} /**
* 删出KEY,并返回该key对应的数据
*/
public Object remove(String key) {
lock.lock();
try {
Node n = cache.remove(key);
if (n == null) {
return null;
} else {
expireQueue.remove(n);
return n.value;
}
} finally {
lock.unlock();
}
} /**
* 删除已经过期的数据
*/
private class SwapExpiredNodeWork implements Runnable { @Override
public void run() { long now = System.currentTimeMillis();
while (true) {
lock.lock();
try {
Node node = expireQueue.peek();
//没有数据了,或者数据都是没有过期的了
if (node == null || node.expireTime > now) {
return;
}
cache.remove(node.key);
expireQueue.poll(); } finally {
lock.unlock();
}
}
}
} private static class Node implements Comparable<Node> {
private String key;
private Object value;
private long expireTime; public Node(String key, Object value, long expireTime) {
this.value = value;
this.key = key;
this.expireTime = expireTime;
} /**
* @see SwapExpiredNodeWork
*/
@Override
public int compareTo(Node o) {
long r = this.expireTime - o.expireTime;
if (r > 0) {
return 1;
}
if (r < 0) {
return -1;
}
return 0;
} }
java实现带过期时间的缓存的更多相关文章
- localstorage实现带过期时间的缓存功能
前言 一般可以使用cookie,localstorage,sessionStorage来实现浏览器端的数据缓存,减少对服务器的请求. 1.cookie数据存放在本地硬盘中,只要在过期时间之前,都是有效 ...
- IIS使用十大原则,(IIS过期时间,IIS缓存设置) 【转载】
1. 自定义错误页虽然自定义错误页很简单,但只有少数管理员有效地利用了它.管理员可以在MMC中将HTTP错误信息映像到服务器上的绝对URL或是某个文件,更为详细的信息可以在这里找到.如果你嫌这太麻烦, ...
- redis 过期时间与缓存
设置过期时间 redis对于存储的键值可以设置过期时间,对于过期了的键值,redis会自动删除. > OK > get price " > expire price (in ...
- Redis -- 过期时间 和 缓存 例子
1.设置 key的生存时间,过期自动删除 exprire key seconds 设置过期时间 秒数 ttl key 查询剩余时间 如果 设置了过期时间.对key进行 set 操作,会清除 ...
- 阿里面试官让我实现一个线程安全并且可以设置过期时间的LRU缓存,我蒙了!
目录 1. LRU 缓存介绍 2. ConcurrentLinkedQueue简单介绍 3. ReadWriteLock简单介绍 4.ScheduledExecutorService 简单介绍 5. ...
- [置顶] 页面缓存,cache,设置缓存过期时间,OutputCache
页面缓存 方法一: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //缓存有数据 if (Cach ...
- 利用GUID唯一标识符并设置它的过期时间
项目中遇到一个小问题,就是把服务器创建的GUID发送给客户端,客户端接收后,下次访问时带上这个GUID, 服务端这边就进行验证,并做相应的处理. 问题是:项目中还需要这个GUID带过期时间,那是如何设 ...
- 可以设置过期时间的Java缓存Map
前言 最近项目需求需要一个类似于redis可以设置过期时间的K,V存储方式.项目前期暂时不引进redis,暂时用java内存代替. 解决方案 1. ExpiringMap 功能简介 : 1.可设置Ma ...
- java操作Redis缓存设置过期时间
关于Redis的概念和应用本文就不再详解了,说一下怎么在java应用中设置过期时间. 在应用中我们会需要使用redis设置过期时间,比如单点登录中我们需要随机生成一个token作为key,将用户的信息 ...
随机推荐
- 【原】Python基础-字典
字典是Python唯一内建的映射类型.键可以是数字,字符串和元组. 1 字典的创建 方法一:直接创建 例如: >>> dict = {'key1':'value1', 20: 80} ...
- java大型互联网项目大流量高并发所需的技术
互联网一般运行技术:webservice,jquery,访问量,缓存,数据安全等,JAVA后台就比较多了,不过,像这种大型的互联网项目,基本框架都有了,你需要做的就是熟悉业务,熟悉他们公司所用的框架, ...
- Alpha项目冲刺! Day7-总结
各个成员今日完成的任务 林恩:任务分工,博客撰写,辅助调试安卓端 李震:修改安卓框架,调试安卓端 胡彤:完善服务端,搭建服务端数据库 李杰:研究了测试工具UiAutomator和MonkeyRunne ...
- rpm包和deb分别是什么?
一.RMP 是 LINUX 下的一种软件的可执行程序,你只要安装它就可以了.这种软件安装包通常是一个RPM包(Redhat Linux Packet Manager,就是Redhat的包管理器),后缀 ...
- Flutter移动电商实战 --(40)路由_Fluro的全局注入和使用方法
路由注册到顶层,使每个页面都可以使用,注册到顶层就需要在main.dart中 main.dart注册路由 注入 onGenerateRoute是MaterialApp自带的路由配置项, 首页跳转到详细 ...
- RVS PA-1800 功放参数
RVS PA-1800大功率功放技术参数: 文章来源:外星人来地球 欢迎关注,有问题一起学习欢迎留言.评论
- p2p通信原理及实现
1.简介 当今互联网到处存在着一些中间件(MIddleBoxes),如NAT和防火墙,导致两个(不在同一内网)中的客户端无法直接通信.这些问题即便是到了IPV6时代也会存在,因为即使不需要NAT,但还 ...
- LiquiBase实战总结
LiquiBase概述 Liquibase是一个用于跟踪.管理和应用数据库变化的开源的数据库重构工具.它将所有数据库的变化(包括结构和数据)都保存在XML文件中,便于版本控制. Liquibase具备 ...
- Centos7.4服务器安装Laravel5.7详细讲解(2018-10-27)
一.在阿里云或者腾讯云选择Centos7并购买服务器 二.安装宝塔面板和php运行环境 1.输入命令 yum install -y wget && wget -O install.sh ...
- 010-多线程-JUC集合-Queue-ConcurrentLinkedQueue
一.概述 ConcurrentLinkedQueue是线程安全的队列,它适用于“高并发”的场景. 它是一个基于链接节点的无界线程安全队列,按照 FIFO(先进先出)原则对元素进行排序.队列元素中不可以 ...