java - 自定义带清除策略的cache
介绍:这就是个高级些的玩具,考验的是大家对于 “优先队列” 的理解。
功能:自定义 cache,达到设置的时间,自动清除缓存的数据。
package com.yt.test.callback2;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* 延迟队列元素,未达到指定时间,则不可使用此对象,单独使用也是不错的工具类
*
* @author ChenSS on 2017年9月13日
* @param <T>
*/
public class DelayItem<T> implements Delayed {
private long timeout;
private long endTime;
private T item;
public DelayItem(T item, long timeout) {
this.item = item;
this.timeout = timeout;
this.endTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS);
}
public DelayItem(T item, long timeout, TimeUnit unit) {
this.item = item;
this.timeout = timeout;
this.endTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, unit);
}
public T getItem() {
return this.item;
}
public long getTimeout() {
return timeout;
}
/**
* 重置结束时间
*
* @throws TimeoutException
* 如果已经结束,不可被重置
*/
public void reset() throws TimeoutException {
if (System.nanoTime() > endTime)
throw new TimeoutException("The current object has timeout, can not be reset");
this.endTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS);
}
/**
* 预计结束时间-当前时间 = 剩余停滞时间(当数值小于零时此对象可用)
*
* @return 纳秒(未达到超时时间对象不可用)
*/
@Override
public long getDelay(TimeUnit unit) {
return unit.convert((endTime - System.nanoTime()), TimeUnit.NANOSECONDS);
}
/**
* 取出结束时间最早的
*/
@Override
public int compareTo(Delayed other) {
if (other == this)
return 0;
if (other instanceof DelayItem) {
long diff = endTime - ((DelayItem<?>) other).endTime;
return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1);
}
long diff = (getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS));
return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((item == null) ? 0 : item.hashCode());
return result;
}
/**
* 重写此方法方便在多数集合中以Item值比较DelayItem是否是同一个
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DelayItem<?> other = (DelayItem<?>) obj;
if (item == null) {
if (other.item != null)
return false;
} else if (!item.equals(other.item))
return false;
return true;
}
}
package com.yt.test.callback2;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.TimeLimitExceededException;
/**
*
* @author ChenSS on 2017年9月13日
* @param <K>
* @param <V>
*/
public class Cache<K, V> {
private Logger logger = Logger.getLogger(Cache.class.getName());
private DelayQueue<DelayItem<K>> q = new DelayQueue<>();
/**
* 多线程安全的Maps
*/
private ConcurrentMap<K, V> maps = new ConcurrentHashMap<K, V>();
private long liveTime;
/**
* 守护进程
*/
private Thread daemonThread;
public Cache(long liveTime) {
this.liveTime = liveTime;
Runnable daemonTask = new Runnable() {
public void run() {
daemonCheck();
}
};
daemonThread = new Thread(daemonTask);
daemonThread.setDaemon(true);
daemonThread.setName("Cache Daemon");
daemonThread.start();
}
public void put(K key, V value) {
this.put(key, value, liveTime, TimeUnit.MILLISECONDS);
}
public void put(K key, V value, long outtime) {
this.put(key, value, outtime, TimeUnit.MILLISECONDS);
}
public void put(K key, V value, long outtime, TimeUnit timeUnit) {
if (outtime <= 0) {
try {
throw new TimeLimitExceededException("Cache livetime below 0");
} catch (TimeLimitExceededException e) {
e.printStackTrace();
}
}
V oldValue = maps.put(key, value);
if (oldValue != null)
q.remove(key);
q.put(new DelayItem<K>(key, outtime, timeUnit));
}
public V get(K key) {
return maps.get(key);
}
private void daemonCheck() {
if (logger.isLoggable(Level.INFO))
logger.info("cache service started.");
for (;;) {
try {
DelayItem<K> delayItem = q.take();
if (delayItem != null)
maps.remove(delayItem.getItem());
} catch (InterruptedException e) {
if (logger.isLoggable(Level.SEVERE))
logger.log(Level.SEVERE, e.getMessage(), e);
e.printStackTrace();
break;
}
}
if (logger.isLoggable(Level.INFO))
logger.info("cache service stopped.");
}
}
package com.yt.test.callback2;
public class Test {
public static void main(String[] args) throws InterruptedException {
Cache<String, Integer> cache = new Cache<>(4000);
cache.put("AAAA", 3);
cache.put("BBBB", 4, 4000);
System.out.println(cache.get("AAAA"));
Thread.sleep(3000);
System.out.println(cache.get("BBBB"));
Thread.sleep(1200);
System.out.println(cache.get("AAAA"));
System.out.println(cache.get("BBBB"));
}
}
疯狂的妞妞 :每一天,做什么都好,不要什么都不做!
分类:
common
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY