mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
change line sep
This commit is contained in:
@@ -1,172 +1,172 @@
|
||||
package cn.hutool.cache;
|
||||
|
||||
import cn.hutool.cache.impl.CacheObj;
|
||||
import cn.hutool.core.lang.func.Func0;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* 缓存接口
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @author Looly, jodd
|
||||
*/
|
||||
public interface Cache<K, V> extends Iterable<V>, Serializable {
|
||||
|
||||
/**
|
||||
* 返回缓存容量,<code>0</code>表示无大小限制
|
||||
*
|
||||
* @return 返回缓存容量,<code>0</code>表示无大小限制
|
||||
*/
|
||||
int capacity();
|
||||
|
||||
/**
|
||||
* 缓存失效时长, <code>0</code> 表示没有设置,单位毫秒
|
||||
*
|
||||
* @return 缓存失效时长, <code>0</code> 表示没有设置,单位毫秒
|
||||
*/
|
||||
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</code>
|
||||
* <p>
|
||||
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
|
||||
* <p>
|
||||
* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
|
||||
*
|
||||
* @param key 键
|
||||
* @return 键对应的对象
|
||||
* @see #get(Object, boolean)
|
||||
*/
|
||||
default V get(K key) {
|
||||
return get(key, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
|
||||
* <p>
|
||||
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
|
||||
* <p>
|
||||
* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
|
||||
*
|
||||
* @param key 键
|
||||
* @param supplier 如果不存在回调方法,用于生产值对象
|
||||
* @return 值对象
|
||||
*/
|
||||
default V get(K key, Func0<V> supplier) {
|
||||
return get(key, true, supplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
|
||||
* <p>
|
||||
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
|
||||
* <p>
|
||||
* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
|
||||
*
|
||||
* @param key 键
|
||||
* @param isUpdateLastAccess 是否更新最后访问时间,即重新计算超时时间。
|
||||
* @param supplier 如果不存在回调方法,用于生产值对象
|
||||
* @return 值对象
|
||||
*/
|
||||
V get(K key, boolean isUpdateLastAccess, Func0<V> supplier);
|
||||
|
||||
/**
|
||||
* 从缓存中获得对象,当对象不在缓存中或已经过期返回<code>null</code>
|
||||
* <p>
|
||||
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache;
|
||||
|
||||
import cn.hutool.cache.impl.CacheObj;
|
||||
import cn.hutool.core.lang.func.Func0;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* 缓存接口
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @author Looly, jodd
|
||||
*/
|
||||
public interface Cache<K, V> extends Iterable<V>, Serializable {
|
||||
|
||||
/**
|
||||
* 返回缓存容量,<code>0</code>表示无大小限制
|
||||
*
|
||||
* @return 返回缓存容量,<code>0</code>表示无大小限制
|
||||
*/
|
||||
int capacity();
|
||||
|
||||
/**
|
||||
* 缓存失效时长, <code>0</code> 表示没有设置,单位毫秒
|
||||
*
|
||||
* @return 缓存失效时长, <code>0</code> 表示没有设置,单位毫秒
|
||||
*/
|
||||
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</code>
|
||||
* <p>
|
||||
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
|
||||
* <p>
|
||||
* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
|
||||
*
|
||||
* @param key 键
|
||||
* @return 键对应的对象
|
||||
* @see #get(Object, boolean)
|
||||
*/
|
||||
default V get(K key) {
|
||||
return get(key, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
|
||||
* <p>
|
||||
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
|
||||
* <p>
|
||||
* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
|
||||
*
|
||||
* @param key 键
|
||||
* @param supplier 如果不存在回调方法,用于生产值对象
|
||||
* @return 值对象
|
||||
*/
|
||||
default V get(K key, Func0<V> supplier) {
|
||||
return get(key, true, supplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
|
||||
* <p>
|
||||
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
|
||||
* <p>
|
||||
* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
|
||||
*
|
||||
* @param key 键
|
||||
* @param isUpdateLastAccess 是否更新最后访问时间,即重新计算超时时间。
|
||||
* @param supplier 如果不存在回调方法,用于生产值对象
|
||||
* @return 值对象
|
||||
*/
|
||||
V get(K key, boolean isUpdateLastAccess, Func0<V> supplier);
|
||||
|
||||
/**
|
||||
* 从缓存中获得对象,当对象不在缓存中或已经过期返回<code>null</code>
|
||||
* <p>
|
||||
* 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
@@ -1,20 +1,20 @@
|
||||
package cn.hutool.cache;
|
||||
|
||||
/**
|
||||
* 缓存监听,用于实现缓存操作时的回调监听,例如缓存对象的移除事件等
|
||||
*
|
||||
* @param <K> 缓存键
|
||||
* @param <V> 缓存值
|
||||
* @author looly
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public interface CacheListener<K, V> {
|
||||
|
||||
/**
|
||||
* 对象移除回调
|
||||
*
|
||||
* @param key 键
|
||||
* @param cachedObject 被缓存的对象
|
||||
*/
|
||||
void onRemove(K key, V cachedObject);
|
||||
}
|
||||
package cn.hutool.cache;
|
||||
|
||||
/**
|
||||
* 缓存监听,用于实现缓存操作时的回调监听,例如缓存对象的移除事件等
|
||||
*
|
||||
* @param <K> 缓存键
|
||||
* @param <V> 缓存值
|
||||
* @author looly
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public interface CacheListener<K, V> {
|
||||
|
||||
/**
|
||||
* 对象移除回调
|
||||
*
|
||||
* @param key 键
|
||||
* @param cachedObject 被缓存的对象
|
||||
*/
|
||||
void onRemove(K key, V cachedObject);
|
||||
}
|
||||
|
@@ -1,128 +1,128 @@
|
||||
package cn.hutool.cache;
|
||||
|
||||
import cn.hutool.cache.impl.FIFOCache;
|
||||
import cn.hutool.cache.impl.LFUCache;
|
||||
import cn.hutool.cache.impl.LRUCache;
|
||||
import cn.hutool.cache.impl.NoCache;
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import cn.hutool.cache.impl.WeakCache;
|
||||
|
||||
/**
|
||||
* 缓存工具类
|
||||
* @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<>();
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache;
|
||||
|
||||
import cn.hutool.cache.impl.FIFOCache;
|
||||
import cn.hutool.cache.impl.LFUCache;
|
||||
import cn.hutool.cache.impl.LRUCache;
|
||||
import cn.hutool.cache.impl.NoCache;
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import cn.hutool.cache.impl.WeakCache;
|
||||
|
||||
/**
|
||||
* 缓存工具类
|
||||
* @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<>();
|
||||
}
|
||||
}
|
||||
|
@@ -1,82 +1,82 @@
|
||||
package cn.hutool.cache;
|
||||
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 全局缓存清理定时器池,用于在需要过期支持的缓存对象中超时任务池
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public enum GlobalPruneTimer {
|
||||
/**
|
||||
* 单例对象
|
||||
*/
|
||||
INSTANCE;
|
||||
|
||||
/**
|
||||
* 缓存任务计数
|
||||
*/
|
||||
private final AtomicInteger cacheTaskNumber = new AtomicInteger(1);
|
||||
|
||||
/**
|
||||
* 定时器
|
||||
*/
|
||||
private ScheduledExecutorService pruneTimer;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
GlobalPruneTimer() {
|
||||
create();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动定时任务
|
||||
*
|
||||
* @param task 任务
|
||||
* @param delay 周期
|
||||
* @return {@link ScheduledFuture}对象,可手动取消此任务
|
||||
*/
|
||||
public ScheduledFuture<?> schedule(Runnable task, long delay) {
|
||||
return this.pruneTimer.scheduleAtFixedRate(task, delay, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建定时器
|
||||
*/
|
||||
public void create() {
|
||||
if (null != pruneTimer) {
|
||||
shutdownNow();
|
||||
}
|
||||
this.pruneTimer = new ScheduledThreadPoolExecutor(1, r -> ThreadUtil.newThread(r, StrUtil.format("Pure-Timer-{}", cacheTaskNumber.getAndIncrement())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁全局定时器
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (null != pruneTimer) {
|
||||
pruneTimer.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁全局定时器
|
||||
*
|
||||
* @return 销毁时未被执行的任务列表
|
||||
*/
|
||||
public List<Runnable> shutdownNow() {
|
||||
if (null != pruneTimer) {
|
||||
return pruneTimer.shutdownNow();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache;
|
||||
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 全局缓存清理定时器池,用于在需要过期支持的缓存对象中超时任务池
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public enum GlobalPruneTimer {
|
||||
/**
|
||||
* 单例对象
|
||||
*/
|
||||
INSTANCE;
|
||||
|
||||
/**
|
||||
* 缓存任务计数
|
||||
*/
|
||||
private final AtomicInteger cacheTaskNumber = new AtomicInteger(1);
|
||||
|
||||
/**
|
||||
* 定时器
|
||||
*/
|
||||
private ScheduledExecutorService pruneTimer;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
GlobalPruneTimer() {
|
||||
create();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动定时任务
|
||||
*
|
||||
* @param task 任务
|
||||
* @param delay 周期
|
||||
* @return {@link ScheduledFuture}对象,可手动取消此任务
|
||||
*/
|
||||
public ScheduledFuture<?> schedule(Runnable task, long delay) {
|
||||
return this.pruneTimer.scheduleAtFixedRate(task, delay, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建定时器
|
||||
*/
|
||||
public void create() {
|
||||
if (null != pruneTimer) {
|
||||
shutdownNow();
|
||||
}
|
||||
this.pruneTimer = new ScheduledThreadPoolExecutor(1, r -> ThreadUtil.newThread(r, StrUtil.format("Pure-Timer-{}", cacheTaskNumber.getAndIncrement())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁全局定时器
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (null != pruneTimer) {
|
||||
pruneTimer.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁全局定时器
|
||||
*
|
||||
* @return 销毁时未被执行的任务列表
|
||||
*/
|
||||
public List<Runnable> shutdownNow() {
|
||||
if (null != pruneTimer) {
|
||||
return pruneTimer.shutdownNow();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -1,134 +1,134 @@
|
||||
package cn.hutool.cache.file;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
|
||||
/**
|
||||
* 文件缓存,以解决频繁读取文件引起的性能问题
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractFileCache implements Serializable{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 容量 */
|
||||
protected final int capacity;
|
||||
/** 缓存的最大文件大小,文件大于此大小时将不被缓存 */
|
||||
protected final int maxFileSize;
|
||||
/** 默认超时时间,0表示无默认超时 */
|
||||
protected final long timeout;
|
||||
/** 缓存实现 */
|
||||
protected final Cache<File, byte[]> cache;
|
||||
|
||||
/** 已使用缓存空间 */
|
||||
protected int usedSize;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 文件最大大小
|
||||
* @param timeout 默认超时时间,0表示无默认超时
|
||||
*/
|
||||
public AbstractFileCache(int capacity, int maxFileSize, long timeout) {
|
||||
this.capacity = capacity;
|
||||
this.maxFileSize = maxFileSize;
|
||||
this.timeout = timeout;
|
||||
this.cache = initCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 缓存容量(byte数)
|
||||
*/
|
||||
public int capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 已使用空间大小(byte数)
|
||||
*/
|
||||
public int getUsedSize() {
|
||||
return usedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 允许被缓存文件的最大byte数
|
||||
*/
|
||||
public int maxFileSize() {
|
||||
return maxFileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 缓存的文件数
|
||||
*/
|
||||
public int getCachedFilesCount() {
|
||||
return cache.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 超时时间
|
||||
*/
|
||||
public long timeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存
|
||||
*/
|
||||
public void clear() {
|
||||
cache.clear();
|
||||
usedSize = 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- get
|
||||
|
||||
/**
|
||||
* 获得缓存过的文件bytes
|
||||
* @param path 文件路径
|
||||
* @return 缓存过的文件bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public byte[] getFileBytes(String path) throws IORuntimeException {
|
||||
return getFileBytes(new File(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存过的文件bytes
|
||||
* @param file 文件
|
||||
* @return 缓存过的文件bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public byte[] getFileBytes(File file) throws IORuntimeException {
|
||||
byte[] bytes = cache.get(file);
|
||||
if (bytes != null) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// add file
|
||||
bytes = FileUtil.readBytes(file);
|
||||
|
||||
if ((maxFileSize != 0) && (file.length() > maxFileSize)) {
|
||||
//大于缓存空间,不缓存,直接返回
|
||||
return bytes;
|
||||
}
|
||||
|
||||
usedSize += bytes.length;
|
||||
|
||||
//文件放入缓存,如果usedSize > capacity,purge()方法将被调用
|
||||
cache.put(file, bytes);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- protected method start
|
||||
/**
|
||||
* 初始化实现文件缓存的缓存对象
|
||||
* @return {@link Cache}
|
||||
*/
|
||||
protected abstract Cache<File, byte[]> initCache();
|
||||
// ---------------------------------------------------------------- protected method end
|
||||
|
||||
}
|
||||
package cn.hutool.cache.file;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
|
||||
/**
|
||||
* 文件缓存,以解决频繁读取文件引起的性能问题
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractFileCache implements Serializable{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 容量 */
|
||||
protected final int capacity;
|
||||
/** 缓存的最大文件大小,文件大于此大小时将不被缓存 */
|
||||
protected final int maxFileSize;
|
||||
/** 默认超时时间,0表示无默认超时 */
|
||||
protected final long timeout;
|
||||
/** 缓存实现 */
|
||||
protected final Cache<File, byte[]> cache;
|
||||
|
||||
/** 已使用缓存空间 */
|
||||
protected int usedSize;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 文件最大大小
|
||||
* @param timeout 默认超时时间,0表示无默认超时
|
||||
*/
|
||||
public AbstractFileCache(int capacity, int maxFileSize, long timeout) {
|
||||
this.capacity = capacity;
|
||||
this.maxFileSize = maxFileSize;
|
||||
this.timeout = timeout;
|
||||
this.cache = initCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 缓存容量(byte数)
|
||||
*/
|
||||
public int capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 已使用空间大小(byte数)
|
||||
*/
|
||||
public int getUsedSize() {
|
||||
return usedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 允许被缓存文件的最大byte数
|
||||
*/
|
||||
public int maxFileSize() {
|
||||
return maxFileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 缓存的文件数
|
||||
*/
|
||||
public int getCachedFilesCount() {
|
||||
return cache.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 超时时间
|
||||
*/
|
||||
public long timeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存
|
||||
*/
|
||||
public void clear() {
|
||||
cache.clear();
|
||||
usedSize = 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- get
|
||||
|
||||
/**
|
||||
* 获得缓存过的文件bytes
|
||||
* @param path 文件路径
|
||||
* @return 缓存过的文件bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public byte[] getFileBytes(String path) throws IORuntimeException {
|
||||
return getFileBytes(new File(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存过的文件bytes
|
||||
* @param file 文件
|
||||
* @return 缓存过的文件bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public byte[] getFileBytes(File file) throws IORuntimeException {
|
||||
byte[] bytes = cache.get(file);
|
||||
if (bytes != null) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// add file
|
||||
bytes = FileUtil.readBytes(file);
|
||||
|
||||
if ((maxFileSize != 0) && (file.length() > maxFileSize)) {
|
||||
//大于缓存空间,不缓存,直接返回
|
||||
return bytes;
|
||||
}
|
||||
|
||||
usedSize += bytes.length;
|
||||
|
||||
//文件放入缓存,如果usedSize > capacity,purge()方法将被调用
|
||||
cache.put(file, bytes);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- protected method start
|
||||
/**
|
||||
* 初始化实现文件缓存的缓存对象
|
||||
* @return {@link Cache}
|
||||
*/
|
||||
protected abstract Cache<File, byte[]> initCache();
|
||||
// ---------------------------------------------------------------- protected method end
|
||||
|
||||
}
|
||||
|
@@ -1,63 +1,63 @@
|
||||
package cn.hutool.cache.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.impl.LFUCache;
|
||||
|
||||
/**
|
||||
* 使用LFU缓存文件,以解决频繁读取文件引起的性能问题
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class LFUFileCache extends AbstractFileCache{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 最大文件大小为缓存容量的一半<br>
|
||||
* 默认无超时
|
||||
* @param capacity 缓存容量
|
||||
*/
|
||||
public LFUFileCache(int capacity) {
|
||||
this(capacity, capacity / 2, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 默认无超时
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 最大文件大小
|
||||
*/
|
||||
public LFUFileCache(int capacity, int maxFileSize) {
|
||||
this(capacity, maxFileSize, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 文件最大大小
|
||||
* @param timeout 默认超时时间,0表示无默认超时
|
||||
*/
|
||||
public LFUFileCache(int capacity, int maxFileSize, long timeout) {
|
||||
super(capacity, maxFileSize, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cache<File, byte[]> initCache() {
|
||||
return new LFUCache<File, byte[]>(LFUFileCache.this.capacity, LFUFileCache.this.timeout) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public boolean isFull() {
|
||||
return LFUFileCache.this.usedSize > this.capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove(File key, byte[] cachedObject) {
|
||||
usedSize -= cachedObject.length;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
package cn.hutool.cache.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.impl.LFUCache;
|
||||
|
||||
/**
|
||||
* 使用LFU缓存文件,以解决频繁读取文件引起的性能问题
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class LFUFileCache extends AbstractFileCache{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 最大文件大小为缓存容量的一半<br>
|
||||
* 默认无超时
|
||||
* @param capacity 缓存容量
|
||||
*/
|
||||
public LFUFileCache(int capacity) {
|
||||
this(capacity, capacity / 2, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 默认无超时
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 最大文件大小
|
||||
*/
|
||||
public LFUFileCache(int capacity, int maxFileSize) {
|
||||
this(capacity, maxFileSize, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 文件最大大小
|
||||
* @param timeout 默认超时时间,0表示无默认超时
|
||||
*/
|
||||
public LFUFileCache(int capacity, int maxFileSize, long timeout) {
|
||||
super(capacity, maxFileSize, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cache<File, byte[]> initCache() {
|
||||
return new LFUCache<File, byte[]>(LFUFileCache.this.capacity, LFUFileCache.this.timeout) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public boolean isFull() {
|
||||
return LFUFileCache.this.usedSize > this.capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove(File key, byte[] cachedObject) {
|
||||
usedSize -= cachedObject.length;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,63 +1,63 @@
|
||||
package cn.hutool.cache.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.impl.LRUCache;
|
||||
|
||||
/**
|
||||
* 使用LRU缓存文件,以解决频繁读取文件引起的性能问题
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class LRUFileCache extends AbstractFileCache{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 最大文件大小为缓存容量的一半<br>
|
||||
* 默认无超时
|
||||
* @param capacity 缓存容量
|
||||
*/
|
||||
public LRUFileCache(int capacity) {
|
||||
this(capacity, capacity / 2, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 默认无超时
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 最大文件大小
|
||||
*/
|
||||
public LRUFileCache(int capacity, int maxFileSize) {
|
||||
this(capacity, maxFileSize, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 文件最大大小
|
||||
* @param timeout 默认超时时间,0表示无默认超时
|
||||
*/
|
||||
public LRUFileCache(int capacity, int maxFileSize, long timeout) {
|
||||
super(capacity, maxFileSize, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cache<File, byte[]> initCache() {
|
||||
return new LRUCache<File, byte[]>(LRUFileCache.this.capacity, super.timeout) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public boolean isFull() {
|
||||
return LRUFileCache.this.usedSize > this.capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove(File key, byte[] cachedObject) {
|
||||
usedSize -= cachedObject.length;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
package cn.hutool.cache.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.impl.LRUCache;
|
||||
|
||||
/**
|
||||
* 使用LRU缓存文件,以解决频繁读取文件引起的性能问题
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class LRUFileCache extends AbstractFileCache{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 最大文件大小为缓存容量的一半<br>
|
||||
* 默认无超时
|
||||
* @param capacity 缓存容量
|
||||
*/
|
||||
public LRUFileCache(int capacity) {
|
||||
this(capacity, capacity / 2, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 默认无超时
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 最大文件大小
|
||||
*/
|
||||
public LRUFileCache(int capacity, int maxFileSize) {
|
||||
this(capacity, maxFileSize, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param capacity 缓存容量
|
||||
* @param maxFileSize 文件最大大小
|
||||
* @param timeout 默认超时时间,0表示无默认超时
|
||||
*/
|
||||
public LRUFileCache(int capacity, int maxFileSize, long timeout) {
|
||||
super(capacity, maxFileSize, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cache<File, byte[]> initCache() {
|
||||
return new LRUCache<File, byte[]>(LRUFileCache.this.capacity, super.timeout) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public boolean isFull() {
|
||||
return LRUFileCache.this.usedSize > this.capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove(File key, byte[] cachedObject) {
|
||||
usedSize -= cachedObject.length;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 提供针对文件的缓存实现
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* 提供针对文件的缓存实现
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
package cn.hutool.cache.file;
|
@@ -1,90 +1,90 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* 缓存对象
|
||||
* @author Looly
|
||||
*
|
||||
* @param <K> Key类型
|
||||
* @param <V> Value类型
|
||||
*/
|
||||
public class CacheObj<K, V> implements Serializable{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected final K key;
|
||||
protected final V obj;
|
||||
|
||||
/** 上次访问时间 */
|
||||
private volatile long lastAccess;
|
||||
/** 访问次数 */
|
||||
protected AtomicLong accessCount = new AtomicLong();
|
||||
/** 对象存活时长,0表示永久存活*/
|
||||
private final long ttl;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param key 键
|
||||
* @param obj 值
|
||||
* @param ttl 超时时长
|
||||
*/
|
||||
protected CacheObj(K key, V obj, long ttl) {
|
||||
this.key = key;
|
||||
this.obj = obj;
|
||||
this.ttl = ttl;
|
||||
this.lastAccess = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否过期
|
||||
*
|
||||
* @return 是否过期
|
||||
*/
|
||||
boolean isExpired() {
|
||||
if(this.ttl > 0) {
|
||||
// 此处不考虑时间回拨
|
||||
return (System.currentTimeMillis() - this.lastAccess) > this.ttl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取值
|
||||
*
|
||||
* @param isUpdateLastAccess 是否更新最后访问时间
|
||||
* @return 获得对象
|
||||
* @since 4.0.10
|
||||
*/
|
||||
V get(boolean isUpdateLastAccess) {
|
||||
if(isUpdateLastAccess) {
|
||||
lastAccess = System.currentTimeMillis();
|
||||
}
|
||||
accessCount.getAndIncrement();
|
||||
return this.obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取键
|
||||
* @return 键
|
||||
* @since 4.0.10
|
||||
*/
|
||||
public K getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取值
|
||||
* @return 值
|
||||
* @since 4.0.10
|
||||
*/
|
||||
public V getValue() {
|
||||
return this.obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CacheObj [key=" + key + ", obj=" + obj + ", lastAccess=" + lastAccess + ", accessCount=" + accessCount + ", ttl=" + ttl + "]";
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* 缓存对象
|
||||
* @author Looly
|
||||
*
|
||||
* @param <K> Key类型
|
||||
* @param <V> Value类型
|
||||
*/
|
||||
public class CacheObj<K, V> implements Serializable{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected final K key;
|
||||
protected final V obj;
|
||||
|
||||
/** 上次访问时间 */
|
||||
private volatile long lastAccess;
|
||||
/** 访问次数 */
|
||||
protected AtomicLong accessCount = new AtomicLong();
|
||||
/** 对象存活时长,0表示永久存活*/
|
||||
private final long ttl;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param key 键
|
||||
* @param obj 值
|
||||
* @param ttl 超时时长
|
||||
*/
|
||||
protected CacheObj(K key, V obj, long ttl) {
|
||||
this.key = key;
|
||||
this.obj = obj;
|
||||
this.ttl = ttl;
|
||||
this.lastAccess = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否过期
|
||||
*
|
||||
* @return 是否过期
|
||||
*/
|
||||
boolean isExpired() {
|
||||
if(this.ttl > 0) {
|
||||
// 此处不考虑时间回拨
|
||||
return (System.currentTimeMillis() - this.lastAccess) > this.ttl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取值
|
||||
*
|
||||
* @param isUpdateLastAccess 是否更新最后访问时间
|
||||
* @return 获得对象
|
||||
* @since 4.0.10
|
||||
*/
|
||||
V get(boolean isUpdateLastAccess) {
|
||||
if(isUpdateLastAccess) {
|
||||
lastAccess = System.currentTimeMillis();
|
||||
}
|
||||
accessCount.getAndIncrement();
|
||||
return this.obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取键
|
||||
* @return 键
|
||||
* @since 4.0.10
|
||||
*/
|
||||
public K getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取值
|
||||
* @return 值
|
||||
* @since 4.0.10
|
||||
*/
|
||||
public V getValue() {
|
||||
return this.obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CacheObj [key=" + key + ", obj=" + obj + ", lastAccess=" + lastAccess + ", accessCount=" + accessCount + ", ttl=" + ttl + "]";
|
||||
}
|
||||
}
|
||||
|
@@ -1,73 +1,73 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* {@link cn.hutool.cache.impl.AbstractCache} 的CacheObj迭代器.
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @since 4.0.10
|
||||
*/
|
||||
public class CacheObjIterator<K, V> implements Iterator<CacheObj<K, V>>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Iterator<CacheObj<K, V>> iterator;
|
||||
private CacheObj<K, V> nextValue;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param iterator 原{@link Iterator}
|
||||
*/
|
||||
CacheObjIterator(Iterator<CacheObj<K, V>> iterator) {
|
||||
this.iterator = iterator;
|
||||
nextValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否有下一个值
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nextValue != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 下一个值
|
||||
*/
|
||||
@Override
|
||||
public CacheObj<K, V> next() {
|
||||
if (false == hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
final CacheObj<K, V> cachedObject = nextValue;
|
||||
nextValue();
|
||||
return cachedObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中移除没有过期的当前值,此方法不支持
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("Cache values Iterator is not support to modify.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一个值,当不存在则下一个值为null
|
||||
*/
|
||||
private void nextValue() {
|
||||
while (iterator.hasNext()) {
|
||||
nextValue = iterator.next();
|
||||
if (nextValue.isExpired() == false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
nextValue = null;
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* {@link cn.hutool.cache.impl.AbstractCache} 的CacheObj迭代器.
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @since 4.0.10
|
||||
*/
|
||||
public class CacheObjIterator<K, V> implements Iterator<CacheObj<K, V>>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Iterator<CacheObj<K, V>> iterator;
|
||||
private CacheObj<K, V> nextValue;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param iterator 原{@link Iterator}
|
||||
*/
|
||||
CacheObjIterator(Iterator<CacheObj<K, V>> iterator) {
|
||||
this.iterator = iterator;
|
||||
nextValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否有下一个值
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nextValue != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 下一个值
|
||||
*/
|
||||
@Override
|
||||
public CacheObj<K, V> next() {
|
||||
if (false == hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
final CacheObj<K, V> cachedObject = nextValue;
|
||||
nextValue();
|
||||
return cachedObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中移除没有过期的当前值,此方法不支持
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("Cache values Iterator is not support to modify.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一个值,当不存在则下一个值为null
|
||||
*/
|
||||
private void nextValue() {
|
||||
while (iterator.hasNext()) {
|
||||
nextValue = iterator.next();
|
||||
if (nextValue.isExpired() == false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
nextValue = null;
|
||||
}
|
||||
}
|
||||
|
@@ -1,48 +1,48 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* {@link cn.hutool.cache.impl.AbstractCache} 的值迭代器.
|
||||
* @author looly
|
||||
*
|
||||
* @param <V> 迭代对象类型
|
||||
*/
|
||||
public class CacheValuesIterator<V> implements Iterator<V>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final CacheObjIterator<?, V> cacheObjIter;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param iterator 原{@link CacheObjIterator}
|
||||
*/
|
||||
CacheValuesIterator(CacheObjIterator<?, V> iterator) {
|
||||
this.cacheObjIter = iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否有下一个值
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.cacheObjIter.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 下一个值
|
||||
*/
|
||||
@Override
|
||||
public V next() {
|
||||
return cacheObjIter.next().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中移除没有过期的当前值,不支持此方法
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
cacheObjIter.remove();
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* {@link cn.hutool.cache.impl.AbstractCache} 的值迭代器.
|
||||
* @author looly
|
||||
*
|
||||
* @param <V> 迭代对象类型
|
||||
*/
|
||||
public class CacheValuesIterator<V> implements Iterator<V>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final CacheObjIterator<?, V> cacheObjIter;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param iterator 原{@link CacheObjIterator}
|
||||
*/
|
||||
CacheValuesIterator(CacheObjIterator<?, V> iterator) {
|
||||
this.cacheObjIter = iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否有下一个值
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.cacheObjIter.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 下一个值
|
||||
*/
|
||||
@Override
|
||||
public V next() {
|
||||
return cacheObjIter.next().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中移除没有过期的当前值,不支持此方法
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
cacheObjIter.remove();
|
||||
}
|
||||
}
|
||||
|
@@ -1,73 +1,73 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* FIFO(first in first out) 先进先出缓存.
|
||||
*
|
||||
* <p>
|
||||
* 元素不停的加入缓存直到缓存满为止,当缓存满时,清理过期缓存对象,清理后依旧满则删除先入的缓存(链表首部对象)<br>
|
||||
* 优点:简单快速 <br>
|
||||
* 缺点:不灵活,不能保证最常用的对象总是被保留
|
||||
* </p>
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @author Looly
|
||||
*/
|
||||
public class FIFOCache<K, V> extends AbstractCache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造,默认对象不过期
|
||||
*
|
||||
* @param capacity 容量
|
||||
*/
|
||||
public FIFOCache(int capacity) {
|
||||
this(capacity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param capacity 容量
|
||||
* @param timeout 过期时长
|
||||
*/
|
||||
public FIFOCache(int capacity, long timeout) {
|
||||
this.capacity = capacity;
|
||||
this.timeout = timeout;
|
||||
cacheMap = new LinkedHashMap<>(Math.max(1 << 4, capacity >>> 7), 1.0f, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 先进先出的清理策略<br>
|
||||
* 先遍历缓存清理过期的缓存对象,如果清理后还是满的,则删除第一个缓存对象
|
||||
*/
|
||||
@Override
|
||||
protected int pruneCache() {
|
||||
int count = 0;
|
||||
CacheObj<K, V> first = null;
|
||||
|
||||
// 清理过期对象并找出链表头部元素(先入元素)
|
||||
Iterator<CacheObj<K, V>> values = cacheMap.values().iterator();
|
||||
while (values.hasNext()) {
|
||||
CacheObj<K, V> co = values.next();
|
||||
if (co.isExpired()) {
|
||||
values.remove();
|
||||
count++;
|
||||
}
|
||||
if (first == null) {
|
||||
first = co;
|
||||
}
|
||||
}
|
||||
|
||||
// 清理结束后依旧是满的,则删除第一个被缓存的对象
|
||||
if (isFull() && null != first) {
|
||||
cacheMap.remove(first.key);
|
||||
onRemove(first.key, first.obj);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* FIFO(first in first out) 先进先出缓存.
|
||||
*
|
||||
* <p>
|
||||
* 元素不停的加入缓存直到缓存满为止,当缓存满时,清理过期缓存对象,清理后依旧满则删除先入的缓存(链表首部对象)<br>
|
||||
* 优点:简单快速 <br>
|
||||
* 缺点:不灵活,不能保证最常用的对象总是被保留
|
||||
* </p>
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @author Looly
|
||||
*/
|
||||
public class FIFOCache<K, V> extends AbstractCache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造,默认对象不过期
|
||||
*
|
||||
* @param capacity 容量
|
||||
*/
|
||||
public FIFOCache(int capacity) {
|
||||
this(capacity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param capacity 容量
|
||||
* @param timeout 过期时长
|
||||
*/
|
||||
public FIFOCache(int capacity, long timeout) {
|
||||
this.capacity = capacity;
|
||||
this.timeout = timeout;
|
||||
cacheMap = new LinkedHashMap<>(Math.max(1 << 4, capacity >>> 7), 1.0f, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 先进先出的清理策略<br>
|
||||
* 先遍历缓存清理过期的缓存对象,如果清理后还是满的,则删除第一个缓存对象
|
||||
*/
|
||||
@Override
|
||||
protected int pruneCache() {
|
||||
int count = 0;
|
||||
CacheObj<K, V> first = null;
|
||||
|
||||
// 清理过期对象并找出链表头部元素(先入元素)
|
||||
Iterator<CacheObj<K, V>> values = cacheMap.values().iterator();
|
||||
while (values.hasNext()) {
|
||||
CacheObj<K, V> co = values.next();
|
||||
if (co.isExpired()) {
|
||||
values.remove();
|
||||
count++;
|
||||
}
|
||||
if (first == null) {
|
||||
first = co;
|
||||
}
|
||||
}
|
||||
|
||||
// 清理结束后依旧是满的,则删除第一个被缓存的对象
|
||||
if (isFull() && null != first) {
|
||||
cacheMap.remove(first.key);
|
||||
onRemove(first.key, first.obj);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
@@ -1,95 +1,95 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* LFU(least frequently used) 最少使用率缓存<br>
|
||||
* 根据使用次数来判定对象是否被持续缓存<br>
|
||||
* 使用率是通过访问次数计算的。<br>
|
||||
* 当缓存满时清理过期对象。<br>
|
||||
* 清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,以便新对象进入后可以公平计数。
|
||||
*
|
||||
* @author Looly,jodd
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
*/
|
||||
public class LFUCache<K, V> extends AbstractCache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param capacity 容量
|
||||
*/
|
||||
public LFUCache(int capacity) {
|
||||
this(capacity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param capacity 容量
|
||||
* @param timeout 过期时长
|
||||
*/
|
||||
public LFUCache(int capacity, long timeout) {
|
||||
if(Integer.MAX_VALUE == capacity) {
|
||||
capacity -= 1;
|
||||
}
|
||||
|
||||
this.capacity = capacity;
|
||||
this.timeout = timeout;
|
||||
cacheMap = new HashMap<>(capacity + 1, 1.0f);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- prune
|
||||
|
||||
/**
|
||||
* 清理过期对象。<br>
|
||||
* 清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,以便新对象进入后可以公平计数。
|
||||
*
|
||||
* @return 清理个数
|
||||
*/
|
||||
@Override
|
||||
protected int pruneCache() {
|
||||
int count = 0;
|
||||
CacheObj<K, V> comin = null;
|
||||
|
||||
// 清理过期对象并找出访问最少的对象
|
||||
Iterator<CacheObj<K, V>> values = cacheMap.values().iterator();
|
||||
CacheObj<K, V> co;
|
||||
while (values.hasNext()) {
|
||||
co = values.next();
|
||||
if (co.isExpired() == true) {
|
||||
values.remove();
|
||||
onRemove(co.key, co.obj);
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//找出访问最少的对象
|
||||
if (comin == null || co.accessCount.get() < comin.accessCount.get()) {
|
||||
comin = co;
|
||||
}
|
||||
}
|
||||
|
||||
// 减少所有对象访问量,并清除减少后为0的访问对象
|
||||
if (isFull() && comin != null) {
|
||||
long minAccessCount = comin.accessCount.get();
|
||||
|
||||
values = cacheMap.values().iterator();
|
||||
CacheObj<K, V> co1;
|
||||
while (values.hasNext()) {
|
||||
co1 = values.next();
|
||||
if (co1.accessCount.addAndGet(-minAccessCount) <= 0) {
|
||||
values.remove();
|
||||
onRemove(co1.key, co1.obj);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* LFU(least frequently used) 最少使用率缓存<br>
|
||||
* 根据使用次数来判定对象是否被持续缓存<br>
|
||||
* 使用率是通过访问次数计算的。<br>
|
||||
* 当缓存满时清理过期对象。<br>
|
||||
* 清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,以便新对象进入后可以公平计数。
|
||||
*
|
||||
* @author Looly,jodd
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
*/
|
||||
public class LFUCache<K, V> extends AbstractCache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param capacity 容量
|
||||
*/
|
||||
public LFUCache(int capacity) {
|
||||
this(capacity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param capacity 容量
|
||||
* @param timeout 过期时长
|
||||
*/
|
||||
public LFUCache(int capacity, long timeout) {
|
||||
if(Integer.MAX_VALUE == capacity) {
|
||||
capacity -= 1;
|
||||
}
|
||||
|
||||
this.capacity = capacity;
|
||||
this.timeout = timeout;
|
||||
cacheMap = new HashMap<>(capacity + 1, 1.0f);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- prune
|
||||
|
||||
/**
|
||||
* 清理过期对象。<br>
|
||||
* 清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,以便新对象进入后可以公平计数。
|
||||
*
|
||||
* @return 清理个数
|
||||
*/
|
||||
@Override
|
||||
protected int pruneCache() {
|
||||
int count = 0;
|
||||
CacheObj<K, V> comin = null;
|
||||
|
||||
// 清理过期对象并找出访问最少的对象
|
||||
Iterator<CacheObj<K, V>> values = cacheMap.values().iterator();
|
||||
CacheObj<K, V> co;
|
||||
while (values.hasNext()) {
|
||||
co = values.next();
|
||||
if (co.isExpired() == true) {
|
||||
values.remove();
|
||||
onRemove(co.key, co.obj);
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//找出访问最少的对象
|
||||
if (comin == null || co.accessCount.get() < comin.accessCount.get()) {
|
||||
comin = co;
|
||||
}
|
||||
}
|
||||
|
||||
// 减少所有对象访问量,并清除减少后为0的访问对象
|
||||
if (isFull() && comin != null) {
|
||||
long minAccessCount = comin.accessCount.get();
|
||||
|
||||
values = cacheMap.values().iterator();
|
||||
CacheObj<K, V> co1;
|
||||
while (values.hasNext()) {
|
||||
co1 = values.next();
|
||||
if (co1.accessCount.addAndGet(-minAccessCount) <= 0) {
|
||||
values.remove();
|
||||
onRemove(co1.key, co1.obj);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
@@ -1,71 +1,71 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import cn.hutool.core.map.FixedLinkedHashMap;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* LRU (least recently used)最近最久未使用缓存<br>
|
||||
* 根据使用时间来判定对象是否被持续缓存<br>
|
||||
* 当对象被访问时放入缓存,当缓存满了,最久未被使用的对象将被移除。<br>
|
||||
* 此缓存基于LinkedHashMap,因此当被缓存的对象每被访问一次,这个对象的key就到链表头部。<br>
|
||||
* 这个算法简单并且非常快,他比FIFO有一个显著优势是经常使用的对象不太可能被移除缓存。<br>
|
||||
* 缺点是当缓存满时,不能被很快的访问。
|
||||
* @author Looly,jodd
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
*/
|
||||
public class LRUCache<K, V> extends AbstractCache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 默认无超时
|
||||
* @param capacity 容量
|
||||
*/
|
||||
public LRUCache(int capacity) {
|
||||
this(capacity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param capacity 容量
|
||||
* @param timeout 默认超时时间,单位:毫秒
|
||||
*/
|
||||
public LRUCache(int capacity, long timeout) {
|
||||
if(Integer.MAX_VALUE == capacity) {
|
||||
capacity -= 1;
|
||||
}
|
||||
|
||||
this.capacity = capacity;
|
||||
this.timeout = timeout;
|
||||
|
||||
//链表key按照访问顺序排序,调用get方法后,会将这次访问的元素移至头部
|
||||
cacheMap = new FixedLinkedHashMap<>(capacity);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- prune
|
||||
|
||||
/**
|
||||
* 只清理超时对象,LRU的实现会交给<code>LinkedHashMap</code>
|
||||
*/
|
||||
@Override
|
||||
protected int pruneCache() {
|
||||
if (isPruneExpiredActive() == false) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
Iterator<CacheObj<K, V>> values = cacheMap.values().iterator();
|
||||
CacheObj<K, V> co;
|
||||
while (values.hasNext()) {
|
||||
co = values.next();
|
||||
if (co.isExpired()) {
|
||||
values.remove();
|
||||
onRemove(co.key, co.obj);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import cn.hutool.core.map.FixedLinkedHashMap;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* LRU (least recently used)最近最久未使用缓存<br>
|
||||
* 根据使用时间来判定对象是否被持续缓存<br>
|
||||
* 当对象被访问时放入缓存,当缓存满了,最久未被使用的对象将被移除。<br>
|
||||
* 此缓存基于LinkedHashMap,因此当被缓存的对象每被访问一次,这个对象的key就到链表头部。<br>
|
||||
* 这个算法简单并且非常快,他比FIFO有一个显著优势是经常使用的对象不太可能被移除缓存。<br>
|
||||
* 缺点是当缓存满时,不能被很快的访问。
|
||||
* @author Looly,jodd
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
*/
|
||||
public class LRUCache<K, V> extends AbstractCache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 默认无超时
|
||||
* @param capacity 容量
|
||||
*/
|
||||
public LRUCache(int capacity) {
|
||||
this(capacity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param capacity 容量
|
||||
* @param timeout 默认超时时间,单位:毫秒
|
||||
*/
|
||||
public LRUCache(int capacity, long timeout) {
|
||||
if(Integer.MAX_VALUE == capacity) {
|
||||
capacity -= 1;
|
||||
}
|
||||
|
||||
this.capacity = capacity;
|
||||
this.timeout = timeout;
|
||||
|
||||
//链表key按照访问顺序排序,调用get方法后,会将这次访问的元素移至头部
|
||||
cacheMap = new FixedLinkedHashMap<>(capacity);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- prune
|
||||
|
||||
/**
|
||||
* 只清理超时对象,LRU的实现会交给<code>LinkedHashMap</code>
|
||||
*/
|
||||
@Override
|
||||
protected int pruneCache() {
|
||||
if (isPruneExpiredActive() == false) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
Iterator<CacheObj<K, V>> values = cacheMap.values().iterator();
|
||||
CacheObj<K, V> co;
|
||||
while (values.hasNext()) {
|
||||
co = values.next();
|
||||
if (co.isExpired()) {
|
||||
values.remove();
|
||||
onRemove(co.key, co.obj);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
@@ -1,87 +1,87 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import cn.hutool.cache.GlobalPruneTimer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
/**
|
||||
* 定时缓存<br>
|
||||
* 此缓存没有容量限制,对象只有在过期后才会被移除
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
*/
|
||||
public class TimedCache<K, V> extends AbstractCache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 正在执行的定时任务 */
|
||||
private ScheduledFuture<?> pruneJobFuture;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param timeout 超时(过期)时长,单位毫秒
|
||||
*/
|
||||
public TimedCache(long timeout) {
|
||||
this(timeout, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param timeout 过期时长
|
||||
* @param map 存储缓存对象的map
|
||||
*/
|
||||
public TimedCache(long timeout, Map<K, CacheObj<K, V>> map) {
|
||||
this.capacity = 0;
|
||||
this.timeout = timeout;
|
||||
this.cacheMap = map;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- prune
|
||||
/**
|
||||
* 清理过期对象
|
||||
*
|
||||
* @return 清理数
|
||||
*/
|
||||
@Override
|
||||
protected int pruneCache() {
|
||||
int count = 0;
|
||||
Iterator<CacheObj<K, V>> values = cacheMap.values().iterator();
|
||||
CacheObj<K, V> co;
|
||||
while (values.hasNext()) {
|
||||
co = values.next();
|
||||
if (co.isExpired()) {
|
||||
values.remove();
|
||||
onRemove(co.key, co.obj);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- auto prune
|
||||
/**
|
||||
* 定时清理
|
||||
*
|
||||
* @param delay 间隔时长,单位毫秒
|
||||
*/
|
||||
public void schedulePrune(long delay) {
|
||||
this.pruneJobFuture = GlobalPruneTimer.INSTANCE.schedule(this::prune, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消定时清理
|
||||
*/
|
||||
public void cancelPruneSchedule() {
|
||||
if (null != pruneJobFuture) {
|
||||
pruneJobFuture.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import cn.hutool.cache.GlobalPruneTimer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
/**
|
||||
* 定时缓存<br>
|
||||
* 此缓存没有容量限制,对象只有在过期后才会被移除
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
*/
|
||||
public class TimedCache<K, V> extends AbstractCache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 正在执行的定时任务 */
|
||||
private ScheduledFuture<?> pruneJobFuture;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param timeout 超时(过期)时长,单位毫秒
|
||||
*/
|
||||
public TimedCache(long timeout) {
|
||||
this(timeout, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param timeout 过期时长
|
||||
* @param map 存储缓存对象的map
|
||||
*/
|
||||
public TimedCache(long timeout, Map<K, CacheObj<K, V>> map) {
|
||||
this.capacity = 0;
|
||||
this.timeout = timeout;
|
||||
this.cacheMap = map;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- prune
|
||||
/**
|
||||
* 清理过期对象
|
||||
*
|
||||
* @return 清理数
|
||||
*/
|
||||
@Override
|
||||
protected int pruneCache() {
|
||||
int count = 0;
|
||||
Iterator<CacheObj<K, V>> values = cacheMap.values().iterator();
|
||||
CacheObj<K, V> co;
|
||||
while (values.hasNext()) {
|
||||
co = values.next();
|
||||
if (co.isExpired()) {
|
||||
values.remove();
|
||||
onRemove(co.key, co.obj);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- auto prune
|
||||
/**
|
||||
* 定时清理
|
||||
*
|
||||
* @param delay 间隔时长,单位毫秒
|
||||
*/
|
||||
public void schedulePrune(long delay) {
|
||||
this.pruneJobFuture = GlobalPruneTimer.INSTANCE.schedule(this::prune, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消定时清理
|
||||
*/
|
||||
public void cancelPruneSchedule() {
|
||||
if (null != pruneJobFuture) {
|
||||
pruneJobFuture.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,24 +1,24 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* 弱引用缓存<br>
|
||||
* 对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。<br>
|
||||
* 丢弃某个键时,其条目从映射中有效地移除。<br>
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* @param <K> 键
|
||||
* @param <V> 值
|
||||
* @author looly
|
||||
* @since 3.0.7
|
||||
*/
|
||||
public class WeakCache<K, V> extends TimedCache<K, V>{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public WeakCache(long timeout) {
|
||||
super(timeout, new WeakHashMap<K, CacheObj<K, V>>());
|
||||
}
|
||||
|
||||
}
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* 弱引用缓存<br>
|
||||
* 对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。<br>
|
||||
* 丢弃某个键时,其条目从映射中有效地移除。<br>
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* @param <K> 键
|
||||
* @param <V> 值
|
||||
* @author looly
|
||||
* @since 3.0.7
|
||||
*/
|
||||
public class WeakCache<K, V> extends TimedCache<K, V>{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public WeakCache(long timeout) {
|
||||
super(timeout, new WeakHashMap<K, CacheObj<K, V>>());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 提供各种缓存实现
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* 提供各种缓存实现
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
package cn.hutool.cache.impl;
|
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 提供简易的缓存实现,此模块参考了jodd工具中的Cache模块
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* 提供简易的缓存实现,此模块参考了jodd工具中的Cache模块
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
package cn.hutool.cache;
|
@@ -1,85 +1,85 @@
|
||||
package cn.hutool.cache.test;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.impl.FIFOCache;
|
||||
import cn.hutool.cache.impl.LRUCache;
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 缓存单元测试
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
public class CacheConcurrentTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void fifoCacheTest() {
|
||||
int threadCount = 4000;
|
||||
final Cache<String, String> cache = new FIFOCache<>(3);
|
||||
|
||||
// 由于缓存容量只有3,当加入第四个元素的时候,根据FIFO规则,最先放入的对象将被移除
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
ThreadUtil.execute(() -> {
|
||||
cache.put("key1", "value1", System.currentTimeMillis() * 3);
|
||||
cache.put("key2", "value2", System.currentTimeMillis() * 3);
|
||||
cache.put("key3", "value3", System.currentTimeMillis() * 3);
|
||||
cache.put("key4", "value4", System.currentTimeMillis() * 3);
|
||||
ThreadUtil.sleep(1000);
|
||||
cache.put("key5", "value5", System.currentTimeMillis() * 3);
|
||||
cache.put("key6", "value6", System.currentTimeMillis() * 3);
|
||||
cache.put("key7", "value7", System.currentTimeMillis() * 3);
|
||||
cache.put("key8", "value8", System.currentTimeMillis() * 3);
|
||||
Console.log("put all");
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
ThreadUtil.execute(() -> show(cache));
|
||||
}
|
||||
|
||||
System.out.println("==============================");
|
||||
ThreadUtil.sleep(10000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void lruCacheTest() {
|
||||
int threadCount = 40000;
|
||||
final Cache<String, String> cache = new LRUCache<>(1000);
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
final int index = i;
|
||||
ThreadUtil.execute(() -> {
|
||||
cache.put("key1"+ index, "value1");
|
||||
cache.put("key2"+ index, "value2", System.currentTimeMillis() * 3);
|
||||
|
||||
int size = cache.size();
|
||||
int capacity = cache.capacity();
|
||||
if(size > capacity) {
|
||||
Console.log("{} {}", size, capacity);
|
||||
}
|
||||
ThreadUtil.sleep(1000);
|
||||
size = cache.size();
|
||||
capacity = cache.capacity();
|
||||
if(size > capacity) {
|
||||
Console.log("## {} {}", size, capacity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ThreadUtil.sleep(5000);
|
||||
}
|
||||
|
||||
private void show(Cache<String, String> cache) {
|
||||
|
||||
for (Object tt : cache) {
|
||||
Console.log(tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache.test;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.impl.FIFOCache;
|
||||
import cn.hutool.cache.impl.LRUCache;
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 缓存单元测试
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
public class CacheConcurrentTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void fifoCacheTest() {
|
||||
int threadCount = 4000;
|
||||
final Cache<String, String> cache = new FIFOCache<>(3);
|
||||
|
||||
// 由于缓存容量只有3,当加入第四个元素的时候,根据FIFO规则,最先放入的对象将被移除
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
ThreadUtil.execute(() -> {
|
||||
cache.put("key1", "value1", System.currentTimeMillis() * 3);
|
||||
cache.put("key2", "value2", System.currentTimeMillis() * 3);
|
||||
cache.put("key3", "value3", System.currentTimeMillis() * 3);
|
||||
cache.put("key4", "value4", System.currentTimeMillis() * 3);
|
||||
ThreadUtil.sleep(1000);
|
||||
cache.put("key5", "value5", System.currentTimeMillis() * 3);
|
||||
cache.put("key6", "value6", System.currentTimeMillis() * 3);
|
||||
cache.put("key7", "value7", System.currentTimeMillis() * 3);
|
||||
cache.put("key8", "value8", System.currentTimeMillis() * 3);
|
||||
Console.log("put all");
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
ThreadUtil.execute(() -> show(cache));
|
||||
}
|
||||
|
||||
System.out.println("==============================");
|
||||
ThreadUtil.sleep(10000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void lruCacheTest() {
|
||||
int threadCount = 40000;
|
||||
final Cache<String, String> cache = new LRUCache<>(1000);
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
final int index = i;
|
||||
ThreadUtil.execute(() -> {
|
||||
cache.put("key1"+ index, "value1");
|
||||
cache.put("key2"+ index, "value2", System.currentTimeMillis() * 3);
|
||||
|
||||
int size = cache.size();
|
||||
int capacity = cache.capacity();
|
||||
if(size > capacity) {
|
||||
Console.log("{} {}", size, capacity);
|
||||
}
|
||||
ThreadUtil.sleep(1000);
|
||||
size = cache.size();
|
||||
capacity = cache.capacity();
|
||||
if(size > capacity) {
|
||||
Console.log("## {} {}", size, capacity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ThreadUtil.sleep(5000);
|
||||
}
|
||||
|
||||
private void show(Cache<String, String> cache) {
|
||||
|
||||
for (Object tt : cache) {
|
||||
Console.log(tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,109 +1,109 @@
|
||||
package cn.hutool.cache.test;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 缓存测试用例
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class CacheTest {
|
||||
|
||||
@Test
|
||||
public void fifoCacheTest(){
|
||||
Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
|
||||
fifoCache.setListener((key, value)->{
|
||||
// 监听测试,此测试中只有key1被移除,测试是否监听成功
|
||||
Assert.assertEquals("key1", key);
|
||||
Assert.assertEquals("value1", value);
|
||||
});
|
||||
|
||||
fifoCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
|
||||
fifoCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
|
||||
fifoCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
|
||||
fifoCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
|
||||
|
||||
//由于缓存容量只有3,当加入第四个元素的时候,根据FIFO规则,最先放入的对象将被移除
|
||||
String value1 = fifoCache.get("key1");
|
||||
Assert.assertNull(value1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lfuCacheTest(){
|
||||
Cache<String, String> lfuCache = CacheUtil.newLFUCache(3);
|
||||
lfuCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
|
||||
//使用次数+1
|
||||
lfuCache.get("key1");
|
||||
lfuCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
|
||||
lfuCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
|
||||
lfuCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
|
||||
|
||||
//由于缓存容量只有3,当加入第四个元素的时候,根据LFU规则,最少使用的将被移除(2,3被移除)
|
||||
String value1 = lfuCache.get("key1");
|
||||
String value2 = lfuCache.get("key2");
|
||||
String value3 = lfuCache.get("key3");
|
||||
Assert.assertNotNull(value1);
|
||||
Assert.assertNull(value2);
|
||||
Assert.assertNull(value3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lruCacheTest(){
|
||||
Cache<String, String> lruCache = CacheUtil.newLRUCache(3);
|
||||
//通过实例化对象创建
|
||||
// LRUCache<String, String> lruCache = new LRUCache<String, String>(3);
|
||||
lruCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
|
||||
lruCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
|
||||
lruCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
|
||||
//使用时间推近
|
||||
lruCache.get("key1");
|
||||
lruCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
|
||||
|
||||
String value1 = lruCache.get("key1");
|
||||
Assert.assertNotNull(value1);
|
||||
//由于缓存容量只有3,当加入第四个元素的时候,根据LRU规则,最少使用的将被移除(2被移除)
|
||||
String value2 = lruCache.get("key2");
|
||||
Assert.assertNull(value2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timedCacheTest(){
|
||||
TimedCache<String, String> timedCache = CacheUtil.newTimedCache(4);
|
||||
// TimedCache<String, String> timedCache = new TimedCache<String, String>(DateUnit.SECOND.getMillis() * 3);
|
||||
timedCache.put("key1", "value1", 1);//1毫秒过期
|
||||
timedCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 5);//5秒过期
|
||||
timedCache.put("key3", "value3");//默认过期(4毫秒)
|
||||
timedCache.put("key4", "value4", Long.MAX_VALUE);//永不过期
|
||||
|
||||
//启动定时任务,每5毫秒秒检查一次过期
|
||||
timedCache.schedulePrune(5);
|
||||
//等待5毫秒
|
||||
ThreadUtil.sleep(5);
|
||||
|
||||
//5毫秒后由于value2设置了5毫秒过期,因此只有value2被保留下来
|
||||
String value1 = timedCache.get("key1");
|
||||
Assert.assertNull(value1);
|
||||
String value2 = timedCache.get("key2");
|
||||
Assert.assertEquals("value2", value2);
|
||||
|
||||
//5毫秒后,由于设置了默认过期,key3只被保留4毫秒,因此为null
|
||||
String value3 = timedCache.get("key3");
|
||||
Assert.assertNull(value3);
|
||||
|
||||
String value3Supplier = timedCache.get("key3", () -> "Default supplier");
|
||||
Assert.assertEquals("Default supplier", value3Supplier);
|
||||
|
||||
// 永不过期
|
||||
String value4 = timedCache.get("key4");
|
||||
Assert.assertEquals("value4", value4);
|
||||
|
||||
//取消定时清理
|
||||
timedCache.cancelPruneSchedule();
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache.test;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 缓存测试用例
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class CacheTest {
|
||||
|
||||
@Test
|
||||
public void fifoCacheTest(){
|
||||
Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
|
||||
fifoCache.setListener((key, value)->{
|
||||
// 监听测试,此测试中只有key1被移除,测试是否监听成功
|
||||
Assert.assertEquals("key1", key);
|
||||
Assert.assertEquals("value1", value);
|
||||
});
|
||||
|
||||
fifoCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
|
||||
fifoCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
|
||||
fifoCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
|
||||
fifoCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
|
||||
|
||||
//由于缓存容量只有3,当加入第四个元素的时候,根据FIFO规则,最先放入的对象将被移除
|
||||
String value1 = fifoCache.get("key1");
|
||||
Assert.assertNull(value1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lfuCacheTest(){
|
||||
Cache<String, String> lfuCache = CacheUtil.newLFUCache(3);
|
||||
lfuCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
|
||||
//使用次数+1
|
||||
lfuCache.get("key1");
|
||||
lfuCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
|
||||
lfuCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
|
||||
lfuCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
|
||||
|
||||
//由于缓存容量只有3,当加入第四个元素的时候,根据LFU规则,最少使用的将被移除(2,3被移除)
|
||||
String value1 = lfuCache.get("key1");
|
||||
String value2 = lfuCache.get("key2");
|
||||
String value3 = lfuCache.get("key3");
|
||||
Assert.assertNotNull(value1);
|
||||
Assert.assertNull(value2);
|
||||
Assert.assertNull(value3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lruCacheTest(){
|
||||
Cache<String, String> lruCache = CacheUtil.newLRUCache(3);
|
||||
//通过实例化对象创建
|
||||
// LRUCache<String, String> lruCache = new LRUCache<String, String>(3);
|
||||
lruCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
|
||||
lruCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
|
||||
lruCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
|
||||
//使用时间推近
|
||||
lruCache.get("key1");
|
||||
lruCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
|
||||
|
||||
String value1 = lruCache.get("key1");
|
||||
Assert.assertNotNull(value1);
|
||||
//由于缓存容量只有3,当加入第四个元素的时候,根据LRU规则,最少使用的将被移除(2被移除)
|
||||
String value2 = lruCache.get("key2");
|
||||
Assert.assertNull(value2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timedCacheTest(){
|
||||
TimedCache<String, String> timedCache = CacheUtil.newTimedCache(4);
|
||||
// TimedCache<String, String> timedCache = new TimedCache<String, String>(DateUnit.SECOND.getMillis() * 3);
|
||||
timedCache.put("key1", "value1", 1);//1毫秒过期
|
||||
timedCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 5);//5秒过期
|
||||
timedCache.put("key3", "value3");//默认过期(4毫秒)
|
||||
timedCache.put("key4", "value4", Long.MAX_VALUE);//永不过期
|
||||
|
||||
//启动定时任务,每5毫秒秒检查一次过期
|
||||
timedCache.schedulePrune(5);
|
||||
//等待5毫秒
|
||||
ThreadUtil.sleep(5);
|
||||
|
||||
//5毫秒后由于value2设置了5毫秒过期,因此只有value2被保留下来
|
||||
String value1 = timedCache.get("key1");
|
||||
Assert.assertNull(value1);
|
||||
String value2 = timedCache.get("key2");
|
||||
Assert.assertEquals("value2", value2);
|
||||
|
||||
//5毫秒后,由于设置了默认过期,key3只被保留4毫秒,因此为null
|
||||
String value3 = timedCache.get("key3");
|
||||
Assert.assertNull(value3);
|
||||
|
||||
String value3Supplier = timedCache.get("key3", () -> "Default supplier");
|
||||
Assert.assertEquals("Default supplier", value3Supplier);
|
||||
|
||||
// 永不过期
|
||||
String value4 = timedCache.get("key4");
|
||||
Assert.assertEquals("value4", value4);
|
||||
|
||||
//取消定时清理
|
||||
timedCache.cancelPruneSchedule();
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +1,19 @@
|
||||
package cn.hutool.cache.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import cn.hutool.cache.file.LFUFileCache;
|
||||
|
||||
/**
|
||||
* 文件缓存单元测试
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
public class FileCacheTest {
|
||||
@Test
|
||||
public void lfuFileCacheTest() {
|
||||
LFUFileCache cache = new LFUFileCache(1000, 500, 2000);
|
||||
Assert.assertNotNull(cache);
|
||||
}
|
||||
}
|
||||
package cn.hutool.cache.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import cn.hutool.cache.file.LFUFileCache;
|
||||
|
||||
/**
|
||||
* 文件缓存单元测试
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
public class FileCacheTest {
|
||||
@Test
|
||||
public void lfuFileCacheTest() {
|
||||
LFUFileCache cache = new LFUFileCache(1000, 500, 2000);
|
||||
Assert.assertNotNull(cache);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user