cn.hutool.core.lang.SimpleCache Maven / Gradle / Ivy
package cn.hutool.core.lang;
import cn.hutool.core.collection.TransIter;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.map.WeakConcurrentMap;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Predicate;
/**
* 简单缓存,无超时实现,默认使用{@link WeakConcurrentMap}实现缓存自动清理
*
* @param 键类型
* @param 值类型
* @author Looly
*/
public class SimpleCache implements Iterable>, Serializable {
private static final long serialVersionUID = 1L;
/**
* 池
*/
private final Map, V> rawMap;
// 乐观读写锁
private final ReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 写的时候每个key一把锁,降低锁的粒度
*/
protected final Map keyLockMap = new ConcurrentHashMap<>();
/**
* 构造,默认使用{@link WeakHashMap}实现缓存自动清理
*/
public SimpleCache() {
this(new WeakConcurrentMap<>());
}
/**
* 构造
*
* 通过自定义Map初始化,可以自定义缓存实现。
* 比如使用{@link WeakHashMap}则会自动清理key,使用HashMap则不会清理
* 同时,传入的Map对象也可以自带初始化的键值对,防止在get时创建
*
*
* @param initMap 初始Map,用于定义Map类型
*/
public SimpleCache(Map, V> initMap) {
this.rawMap = initMap;
}
/**
* 从缓存池中查找值
*
* @param key 键
* @return 值
*/
public V get(K key) {
lock.readLock().lock();
try {
return rawMap.get(MutableObj.of(key));
} finally {
lock.readLock().unlock();
}
}
/**
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
*
* @param key 键
* @param supplier 如果不存在回调方法,用于生产值对象
* @return 值对象
*/
public V get(K key, Func0 supplier) {
return get(key, null, supplier);
}
/**
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
*
* @param key 键
* @param validPredicate 检查结果对象是否可用,如是否断开连接等
* @param supplier 如果不存在回调方法或结果不可用,用于生产值对象
* @return 值对象
* @since 5.7.9
*/
public V get(K key, Predicate validPredicate, Func0 supplier) {
V v = get(key);
if((null != validPredicate && null != v && false == validPredicate.test(v))){
v = null;
}
if (null == v && null != supplier) {
//每个key单独获取一把锁,降低锁的粒度提高并发能力,see pr#1385@Github
final Lock keyLock = keyLockMap.computeIfAbsent(key, k -> new ReentrantLock());
keyLock.lock();
try {
// 双重检查,防止在竞争锁的过程中已经有其它线程写入
v = get(key);
if (null == v || (null != validPredicate && false == validPredicate.test(v))) {
try {
v = supplier.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
put(key, v);
}
} finally {
keyLock.unlock();
keyLockMap.remove(key);
}
}
return v;
}
/**
* 放入缓存
*
* @param key 键
* @param value 值
* @return 值
*/
public V put(K key, V value) {
// 独占写锁
lock.writeLock().lock();
try {
rawMap.put(MutableObj.of(key), value);
} finally {
lock.writeLock().unlock();
}
return value;
}
/**
* 移除缓存
*
* @param key 键
* @return 移除的值
*/
public V remove(K key) {
// 独占写锁
lock.writeLock().lock();
try {
return rawMap.remove(MutableObj.of(key));
} finally {
lock.writeLock().unlock();
}
}
/**
* 清空缓存池
*/
public void clear() {
// 独占写锁
lock.writeLock().lock();
try {
this.rawMap.clear();
} finally {
lock.writeLock().unlock();
}
}
@Override
public Iterator> iterator() {
return new TransIter<>(this.rawMap.entrySet().iterator(), (entry)-> new Map.Entry() {
@Override
public K getKey() {
return entry.getKey().get();
}
@Override
public V getValue() {
return entry.getValue();
}
@Override
public V setValue(V value) {
return entry.setValue(value);
}
});
}
}