mirror of
https://gitee.com/dromara/hutool.git
synced 2025-06-28 13:34:09 +08:00
修复AbstractCache
putWithoutLock方法可能导致的外部资源泄露问题(pr#3958@Github)
This commit is contained in:
parent
698443860f
commit
68bcc8f5de
@ -109,7 +109,9 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
|
|||||||
final MutableObj<K> mKey = MutableObj.of(key);
|
final MutableObj<K> mKey = MutableObj.of(key);
|
||||||
|
|
||||||
// issue#3618 对于替换的键值对,不做满队列检查和清除
|
// issue#3618 对于替换的键值对,不做满队列检查和清除
|
||||||
if (cacheMap.containsKey(mKey)) {
|
final CacheObj<K, V> oldObj = cacheMap.get(mKey);
|
||||||
|
if (null != oldObj) {
|
||||||
|
onRemove(oldObj.key, oldObj.obj);
|
||||||
// 存在相同key,覆盖之
|
// 存在相同key,覆盖之
|
||||||
cacheMap.put(mKey, co);
|
cacheMap.put(mKey, co);
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,8 +17,12 @@
|
|||||||
package cn.hutool.v7.core.cache.impl;
|
package cn.hutool.v7.core.cache.impl;
|
||||||
|
|
||||||
import cn.hutool.v7.core.collection.iter.CopiedIter;
|
import cn.hutool.v7.core.collection.iter.CopiedIter;
|
||||||
|
import cn.hutool.v7.core.collection.set.SetUtil;
|
||||||
|
import cn.hutool.v7.core.lang.mutable.Mutable;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
@ -31,6 +35,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
* @author Looly
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public abstract class LockedCache<K, V> extends AbstractCache<K, V> {
|
public abstract class LockedCache<K, V> extends AbstractCache<K, V> {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,7 +103,15 @@ public abstract class LockedCache<K, V> extends AbstractCache<K, V> {
|
|||||||
public void clear() {
|
public void clear() {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
cacheMap.clear();
|
// 获取所有键的副本
|
||||||
|
final Set<Mutable<K>> keys = SetUtil.of(cacheMap.keySet());
|
||||||
|
CacheObj<K, V> co;
|
||||||
|
for (final Mutable<K> key : keys) {
|
||||||
|
co = removeWithoutLock(key.get());
|
||||||
|
if (null != co) {
|
||||||
|
onRemove(co.key, co.obj); // 触发资源释放
|
||||||
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package cn.hutool.v7.core.cache.impl;
|
|||||||
import cn.hutool.v7.core.cache.GlobalPruneTimer;
|
import cn.hutool.v7.core.cache.GlobalPruneTimer;
|
||||||
import cn.hutool.v7.core.lang.mutable.Mutable;
|
import cn.hutool.v7.core.lang.mutable.Mutable;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -34,6 +35,7 @@ import java.util.concurrent.ScheduledFuture;
|
|||||||
* @param <V> 值类型
|
* @param <V> 值类型
|
||||||
*/
|
*/
|
||||||
public class TimedReentrantCache<K, V> extends LockedCache<K, V> {
|
public class TimedReentrantCache<K, V> extends LockedCache<K, V> {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** 正在执行的定时任务 */
|
/** 正在执行的定时任务 */
|
||||||
|
@ -164,4 +164,22 @@ public class CacheTest {
|
|||||||
assertFalse(ALARM_CACHE.containsKey(1));
|
assertFalse(ALARM_CACHE.containsKey(1));
|
||||||
assertEquals(1, counter.get());
|
assertEquals(1, counter.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReentrantCache类clear()方法、AbstractCache.putWithoutLock方法可能导致资源泄露
|
||||||
|
* https://github.com/chinabugotech/hutool/issues/3957
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void reentrantCache_clear_Method_Test() {
|
||||||
|
AtomicInteger removeCount = new AtomicInteger();
|
||||||
|
Cache<String, String> lruCache = CacheUtil.newLRUCache(4);
|
||||||
|
lruCache.setListener((key, cachedObject) -> removeCount.getAndIncrement());
|
||||||
|
lruCache.put("key1","String1");
|
||||||
|
lruCache.put("key2","String2");
|
||||||
|
lruCache.put("key3","String3");
|
||||||
|
lruCache.put("key1","String4");//key已经存在,原始putWithoutLock方法存在资源泄露
|
||||||
|
lruCache.put("key4","String5");
|
||||||
|
lruCache.clear();//ReentrantCache类clear()方法存在资源泄露
|
||||||
|
Assertions.assertEquals(5, removeCount.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user