mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-12-07 17:48:40 +08:00
ReentrantCache增加setUseKeyLock让用户选择是否使用键锁来增强性能,或者保证安全。(issue#4022@Github)
This commit is contained in:
parent
a0d946b3a8
commit
9f7dedea90
@ -2,7 +2,7 @@
|
||||
# 🚀Changelog
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
# 5.8.40(2025-08-21)
|
||||
# 5.8.40(2025-08-25)
|
||||
|
||||
### 🐣新特性
|
||||
* 【captcha】 `MathGenerator`四则运算方式支持不生成负数结果(pr#1363@Gitee)
|
||||
@ -21,6 +21,7 @@
|
||||
* 【extra 】 修复`QLExpressEngine`allowClassSet无效问题(issue#3994@Github)
|
||||
* 【core 】 修复`StrBuilder`insert插入计算错误问题(issue#ICTSRZ@Gitee)
|
||||
* 【cron 】 修复`CronPatternUtil.nextDateAfter`计算下一个匹配表达式的日期时,计算错误问题(issue#4006@Github)
|
||||
* 【cache 】 `ReentrantCache`增加`setUseKeyLock`让用户选择是否使用键锁来增强性能,或者保证安全。(issue#4022@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
# 5.8.39(2025-06-20)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import cn.hutool.core.collection.CopiedIter;
|
||||
import cn.hutool.core.lang.func.Func0;
|
||||
import cn.hutool.core.lang.mutable.Mutable;
|
||||
|
||||
import java.util.HashSet;
|
||||
@ -24,6 +25,20 @@ public abstract class ReentrantCache<K, V> extends AbstractCache<K, V> {
|
||||
// TODO 最优的解决方案是使用Guava的ConcurrentLinkedHashMap,此处使用简化的互斥锁
|
||||
protected final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private boolean useKeyLock = true;
|
||||
|
||||
/**
|
||||
* 设置是否使用key锁,默认为true
|
||||
*
|
||||
* @param useKeyLock 是否使用key锁
|
||||
* @return this
|
||||
* @since 5.8.40
|
||||
*/
|
||||
public ReentrantCache<K, V> setUseKeyLock(boolean useKeyLock) {
|
||||
this.useKeyLock = useKeyLock;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V object, long timeout) {
|
||||
lock.lock();
|
||||
@ -44,6 +59,36 @@ public abstract class ReentrantCache<K, V> extends AbstractCache<K, V> {
|
||||
return getOrRemoveExpired(key, isUpdateLastAccess, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(final K key, final boolean isUpdateLastAccess, final long timeout, final Func0<V> valueFactory) {
|
||||
if(useKeyLock){
|
||||
// 用户如果允许,则使用key锁,可以减少valueFactory对象创建造成的
|
||||
return super.get(key, isUpdateLastAccess, timeout, valueFactory);
|
||||
}
|
||||
|
||||
V v = get(key, isUpdateLastAccess);
|
||||
|
||||
// 对象不存在,则加锁创建
|
||||
if (null == v && null != valueFactory) {
|
||||
// 按照pr#1385提议,使用key锁可以避免对象创建等待问题,但是会带来循环锁问题,见:issue#4022
|
||||
// 因此此处依旧采用全局锁,在对象创建过程中,全局等待,避免循环锁依赖
|
||||
// 这样避免了循环锁,但是会存在一个缺点,即对象创建过程中,其它线程无法获得锁,从而无法使用缓存,因此需要考虑对象创建的耗时问题
|
||||
lock.lock();
|
||||
try {
|
||||
// 双重检查锁,防止在竞争锁的过程中已经有其它线程写入
|
||||
final CacheObj<K, V> co = getWithoutLock(key);
|
||||
if (null == co) {
|
||||
// supplier的创建是一个耗时过程,此处创建与全局锁无关,而与key锁相关,这样就保证每个key只创建一个value,且互斥
|
||||
v = valueFactory.callWithRuntimeException();
|
||||
put(key, v, timeout);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<CacheObj<K, V>> cacheObjIterator() {
|
||||
CopiedIter<CacheObj<K, V>> copiedIterator;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user