一、TimedCache 是什么?
TimedCache是一个泛型类,它的主要作用通常是在一定时间范围内对特定键值对进行缓存,并且能够根据设定的时间策略来自动清理过期的缓存项。
TimedCache是一种带有时间控制功能的缓存数据结构。在 Java 中,缓存是一种用于临时存储数据的机制,目的是为了减少重复计算或者重复的数据获取操作,提高程序的性能。而TimedCache在此基础上增加了时间维度的管理。
二、常见功能及使用场景
缓存存储:可以将以String为键、BigDecimal为值的键值对存入缓存中,方便后续快速获取,避免重复计算或查询相同的数据。
时间控制:设置缓存项的有效期,一旦超过指定时间,缓存项会被自动视为过期并可能被清理掉。这有助于保证缓存数据的时效性,例如在处理实时金融数据(如汇率、股票价格等,这里值用BigDecimal表示很合适)时,旧的数据在一定时间后就不再有价值,通过定时清理过期缓存可确保获取到相对新的数据。
缓存获取:通过给定的String键,可以快速从缓存中获取对应的BigDecimal值,如果缓存命中则直接返回缓存中的值,提高数据访问效率。
三、使用场景
金融数据处理:如前面提到的汇率、股票价格等数据的缓存。金融数据经常需要实时更新,但在短时间内可能会被多次查询,使用TimedCache<String, BigDecimal>可以缓存这些数据,在有效期内直接从缓存获取,减少对数据源(如金融数据接口)的频繁访问,提高系统响应速度。
电商价格缓存:在电商系统中,商品价格可能会根据促销活动等因素实时变动,但在一定时间段内(比如促销活动期间),对于同一商品的价格查询较为频繁。将商品 ID(可以用String表示)作为键,商品价格(用BigDecimal表示)作为值存入TimedCache,可以在活动期间有效缓存价格数据,提高查询效率。
统计数据缓存:例如网站的实时流量统计数据,以某个统计指标的名称(String)为键,对应的统计数值(可能是BigDecimal类型,如流量的具体数值等)为值进行缓存。这样在短时间内可以快速获取统计数据,并且通过设置合适的时间限制,确保数据能及时更新。
四、使用
1、相关依赖
xml
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.6</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
2、使用
2.1、自定义工具简单使用:
java
private static final TimedCache<String, String> TIMED_CACHE = CacheUtil.newTimedCache(5000);
static {
/** 每5ms检查一次过期 */
TIMED_CACHE.schedulePrune(5);
}
/**
* 存入键值对,提供消逝时间
*
* @param key
* @param value
* @param timeout
*/
public static void put(String key, String value, Long timeout) {
/** 设置消逝时间 */
TIMED_CACHE.put(key, value, timeout);
}
/**
* 每次重新get一次缓存,均会重新刷新消逝时间
* @param key
* @return
*/
public static String get(String key) {
return TIMED_CACHE.get(key);
}
public static void main(String[] args) {
put("haha", "1", 3000L);
ThreadUtil.sleep(2000);
// if (TIMED_CACHE.containsKey("haha")) {
// System.out.println("aa");
// }
System.out.println("第1次结果:" + get("haha"));
ThreadUtil.sleep(2000);
System.out.println("第2次结果:" + get("haha"));
ThreadUtil.sleep(5000);
System.out.println("第3次结果:" + get("haha"));
// 取消定时清理
TIMED_CACHE.cancelPruneSchedule();
}
2.2、糊涂工具使用
CacheUtil具体方法:
java
/**
* 缓存工具类
* @author Looly
*@since 3.0.1
*/
public class CacheUtil {
/**
* 创建FIFO(first in first out) 先进先出缓存.
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
* @param timeout 过期时长,单位:毫秒
* @return {@link FIFOCache}
*/
public static <K, V> FIFOCache<K, V> newFIFOCache(int capacity, long timeout){
return new FIFOCache<>(capacity, timeout);
}
/**
* 创建FIFO(first in first out) 先进先出缓存.
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
* @return {@link FIFOCache}
*/
public static <K, V> FIFOCache<K, V> newFIFOCache(int capacity){
return new FIFOCache<>(capacity);
}
/**
* 创建LFU(least frequently used) 最少使用率缓存.
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
* @param timeout 过期时长,单位:毫秒
* @return {@link LFUCache}
*/
public static <K, V> LFUCache<K, V> newLFUCache(int capacity, long timeout){
return new LFUCache<>(capacity, timeout);
}
/**
* 创建LFU(least frequently used) 最少使用率缓存.
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
* @return {@link LFUCache}
*/
public static <K, V> LFUCache<K, V> newLFUCache(int capacity){
return new LFUCache<>(capacity);
}
/**
* 创建LRU (least recently used)最近最久未使用缓存.
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
* @param timeout 过期时长,单位:毫秒
* @return {@link LRUCache}
*/
public static <K, V> LRUCache<K, V> newLRUCache(int capacity, long timeout){
return new LRUCache<>(capacity, timeout);
}
/**
* 创建LRU (least recently used)最近最久未使用缓存.
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
* @return {@link LRUCache}
*/
public static <K, V> LRUCache<K, V> newLRUCache(int capacity){
return new LRUCache<>(capacity);
}
/**
* 创建定时缓存.
*
* @param <K> Key类型
* @param <V> Value类型
* @param timeout 过期时长,单位:毫秒
* @return {@link TimedCache}
*/
public static <K, V> TimedCache<K, V> newTimedCache(long timeout){
return new TimedCache<>(timeout);
}
/**
* 创建弱引用缓存.
*
* @param <K> Key类型
* @param <V> Value类型
* @param timeout 过期时长,单位:毫秒
* @return {@link WeakCache}
* @since 3.0.7
*/
public static <K, V> WeakCache<K, V> newWeakCache(long timeout){
return new WeakCache<>(timeout);
}
/**
* 创建无缓存实现.
*
* @param <K> Key类型
* @param <V> Value类型
* @return {@link NoCache}
*/
public static <K, V> NoCache<K, V> newNoCache(){
return new NoCache<>();
}
}
Cache接口具体方法:
java
/**
* 缓存接口
*
* @param <K> 键类型
* @param <V> 值类型
* @author Looly, jodd
*/
public interface Cache<K, V> extends Iterable<V>, Serializable {
/**
* 返回缓存容量,{@code 0}表示无大小限制
*
* @return 返回缓存容量,{@code 0}表示无大小限制
*/
int capacity();
/**
* 缓存失效时长, {@code 0} 表示没有设置,单位毫秒
*
* @return 缓存失效时长, {@code 0} 表示没有设置,单位毫秒
*/
long timeout();
/**
* 将对象加入到缓存,使用默认失效时长
*
* @param key 键
* @param object 缓存的对象
* @see Cache#put(Object, Object, long)
*/
void put(K key, V object);
/**
* 将对象加入到缓存,使用指定失效时长<br>
* 如果缓存空间满了,{@link #prune()} 将被调用以获得空间来存放新对象
*
* @param key 键
* @param object 缓存的对象
* @param timeout 失效时长,单位毫秒
*/
void put(K key, V object, long timeout);
/**
* 从缓存中获得对象,当对象不在缓存中或已经过期返回{@code null}
* <p>
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。
* <p>
* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
*
* @param key 键
* @return 键对应的对象
* @see #get(Object, boolean)
*/
default V get(K key) {
return get(key, true);
}
/**
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
* <p>
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。
* <p>
* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
*
* @param key 键
* @param supplier 如果不存在回调方法,用于生产值对象
* @return 值对象
*/
default V get(K key, Func0<V> supplier) {
return get(key, true, supplier);
}
/**
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
* <p>
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。
* <p>
* 每次调用此方法会可选是否刷新最后访问时间,{@code true}表示会重新计算超时时间。
*
* @param key 键
* @param isUpdateLastAccess 是否更新最后访问时间,即重新计算超时时间。
* @param supplier 如果不存在回调方法,用于生产值对象
* @return 值对象
*/
V get(K key, boolean isUpdateLastAccess, Func0<V> supplier);
/**
* 从缓存中获得对象,当对象不在缓存中或已经过期返回{@code null}
* <p>
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。
* <p>
* 每次调用此方法会可选是否刷新最后访问时间,{@code true}表示会重新计算超时时间。
*
* @param key 键
* @param isUpdateLastAccess 是否更新最后访问时间,即重新计算超时时间。
* @return 键对应的对象
*/
V get(K key, boolean isUpdateLastAccess);
/**
* 返回包含键和值得迭代器
*
* @return 缓存对象迭代器
* @since 4.0.10
*/
Iterator<CacheObj<K, V>> cacheObjIterator();
/**
* 从缓存中清理过期对象,清理策略取决于具体实现
*
* @return 清理的缓存对象个数
*/
int prune();
/**
* 缓存是否已满,仅用于有空间限制的缓存对象
*
* @return 缓存是否已满,仅用于有空间限制的缓存对象
*/
boolean isFull();
/**
* 从缓存中移除对象
*
* @param key 键
*/
void remove(K key);
/**
* 清空缓存
*/
void clear();
/**
* 缓存的对象数量
*
* @return 缓存的对象数量
*/
int size();
/**
* 缓存是否为空
*
* @return 缓存是否为空
*/
boolean isEmpty();
/**
* 是否包含key
*
* @param key KEY
* @return 是否包含key
*/
boolean containsKey(K key);
/**
* 设置监听
*
* @param listener 监听
* @return this
* @since 5.5.2
*/
default Cache<K, V> setListener(CacheListener<K, V> listener){
return this;
}
}
使用:创建一个缓存对象,自动清理时间单位为毫秒,自动清理时间为3秒钟
java
public static void main(String[] args) {
TimedCache<String, BigDecimal> dataCache = CacheUtil.newTimedCache(3000);
String k = "key";
BigDecimal v = new BigDecimal("100");
dataCache.put(k,v);
System.out.println("第1次结果:" + dataCache.get(k));
ThreadUtil.sleep(2000);
System.out.println("第2次结果:" + dataCache.get(k));
ThreadUtil.sleep(5000);
System.out.println("第3次结果:" + dataCache.get(k));
System.out.println("第3次结果-get方法:" + dataCache.get(k, () -> v)); //使用此方法,如果为空值就把数据重新赋值并且返回
System.out.println("第4次结果:" + dataCache.get(k));
}