修复AbstractCache.get中锁不一致导致的并发问题

This commit is contained in:
Looly
2024-08-08 15:57:16 +08:00
parent 74ee2c7425
commit 5e680123a7
2 changed files with 7 additions and 12 deletions

View File

@@ -2,7 +2,6 @@ package cn.hutool.cache.impl;
import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheListener;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutableObj;
@@ -130,18 +129,13 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
keyLock.lock();
try {
// 双重检查锁,防止在竞争锁的过程中已经有其它线程写入
final CacheObj<K, V> co = getWithoutLock(key);
if (null == co || co.isExpired()) {
try {
v = supplier.call();
} catch (Exception e) {
// issue#I7RJZT 运行时异常不做包装
throw ExceptionUtil.wrapRuntime(e);
//throw new RuntimeException(e);
}
// issue#3686 由于这个方法内的加锁是get独立锁不和put锁互斥而put和pruneCache会修改cacheMap导致在pruneCache过程中get会有并发问题
// 因此此处需要使用带全局锁的get获取值
v = get(key, isUpdateLastAccess);
if (null == v) {
// supplier的创建是一个耗时过程此处创建与全局锁无关而与key锁相关这样就保证每个key只创建一个value且互斥
v = supplier.callWithRuntimeException();
put(key, v, timeout);
} else {
v = co.get(isUpdateLastAccess);
}
} finally {
keyLock.unlock();