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实现带过期时间的缓存的更多相关文章

  1. localstorage实现带过期时间的缓存功能

    前言 一般可以使用cookie,localstorage,sessionStorage来实现浏览器端的数据缓存,减少对服务器的请求. 1.cookie数据存放在本地硬盘中,只要在过期时间之前,都是有效 ...

  2. IIS使用十大原则,(IIS过期时间,IIS缓存设置) 【转载】

    1. 自定义错误页虽然自定义错误页很简单,但只有少数管理员有效地利用了它.管理员可以在MMC中将HTTP错误信息映像到服务器上的绝对URL或是某个文件,更为详细的信息可以在这里找到.如果你嫌这太麻烦, ...

  3. redis 过期时间与缓存

    设置过期时间 redis对于存储的键值可以设置过期时间,对于过期了的键值,redis会自动删除. > OK > get price " > expire price (in ...

  4. Redis -- 过期时间 和 缓存 例子

    1.设置 key的生存时间,过期自动删除 exprire key  seconds    设置过期时间 秒数 ttl key   查询剩余时间 如果 设置了过期时间.对key进行 set 操作,会清除 ...

  5. 阿里面试官让我实现一个线程安全并且可以设置过期时间的LRU缓存,我蒙了!

    目录 1. LRU 缓存介绍 2. ConcurrentLinkedQueue简单介绍 3. ReadWriteLock简单介绍 4.ScheduledExecutorService 简单介绍 5. ...

  6. [置顶] 页面缓存,cache,设置缓存过期时间,OutputCache

    页面缓存 方法一: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //缓存有数据 if (Cach ...

  7. 利用GUID唯一标识符并设置它的过期时间

    项目中遇到一个小问题,就是把服务器创建的GUID发送给客户端,客户端接收后,下次访问时带上这个GUID, 服务端这边就进行验证,并做相应的处理. 问题是:项目中还需要这个GUID带过期时间,那是如何设 ...

  8. 可以设置过期时间的Java缓存Map

    前言 最近项目需求需要一个类似于redis可以设置过期时间的K,V存储方式.项目前期暂时不引进redis,暂时用java内存代替. 解决方案 1. ExpiringMap 功能简介 : 1.可设置Ma ...

  9. java操作Redis缓存设置过期时间

    关于Redis的概念和应用本文就不再详解了,说一下怎么在java应用中设置过期时间. 在应用中我们会需要使用redis设置过期时间,比如单点登录中我们需要随机生成一个token作为key,将用户的信息 ...

随机推荐

  1. nginx 动态黑名单

    原理: 根据nginx 访问日志记录发现可疑的或者不正常的访问记录记录然后自动添加到nginx的黑名单 起到阻止的作用  可以作为防范少量的ddos攻击 1.首先要格式化nginx的日志(相关内容可以 ...

  2. AOP 与 Spring中AOP使用(上)

    AOP简介 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP是OOP的延续 ...

  3. AI案例

    https://www.bilibili.com/read/cv830627     到底什么是人工智能?人工智能能做什么?这是大家最关心的问题,但说到真正能够理解的话,还是只小部分专业人士.这篇文章 ...

  4. TynSerial自定义对象的序列(还原)

    TynSerial自定义对象的序列(还原) TynSerial是咏南中间件封装的支持数据二进制序列(还原)的类. 对于ORM来说,序列类必须序列(还原)自定义对象. 1)定义一个自定义对象 type ...

  5. angular 中的[ngClass]、[ngStyle]

    <div style="text-align:center"> <h1> Welcome to {{ title }}! </h1> </ ...

  6. 简易的CRM系统案例之SpringMVC+JSP+MySQL+myBatis框架版本

    主要对上一版DAO框架的替换hibernate变成myBatis 简易的CRM系统案例之SpringMVC+JSP+MySQL+hibernate框架版本 src/mybatis.xml <?x ...

  7. spring cloud+.net core搭建微服务架构

    http://www.cnblogs.com/longxianghui/p/7800316.html

  8. Eclipse中把项目导出为war包【我】

    项目右键,Export 全部默认一路下一步,选择一个目标文件夹,确定即可.

  9. VCTravel

    #pragma once #include <osgViewer/Viewer> #include <osgViewer/ViewerEventHandlers> #inclu ...

  10. 获取src 内容

    获取(代码): ].src; // 测试无效 修改(代码): 1 $("#img").attr('src',path);