修复ReentrantCache#getOrRemoveExpired方法丢失onRemove触发问题(pr#1315@Gitee)

This commit is contained in:
Looly 2025-03-03 10:49:48 +08:00
parent bdf3a0a1f0
commit d3941e5dd7
2 changed files with 34 additions and 6 deletions

View File

@ -129,6 +129,7 @@ public abstract class LockedCache<K, V> extends AbstractCache<K, V> {
if(null != co && co.isExpired()){ if(null != co && co.isExpired()){
//过期移除 //过期移除
removeWithoutLock(key); removeWithoutLock(key);
onRemove(co.key, co.obj);
co = null; co = null;
} }
} finally { } finally {

View File

@ -23,6 +23,11 @@ import org.dromara.hutool.core.util.RandomUtil;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
/** /**
* 缓存测试用例 * 缓存测试用例
* @author Looly * @author Looly
@ -35,8 +40,8 @@ public class CacheTest {
final Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3); final Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
fifoCache.setListener((key, value)->{ fifoCache.setListener((key, value)->{
// 监听测试此测试中只有key1被移除测试是否监听成功 // 监听测试此测试中只有key1被移除测试是否监听成功
Assertions.assertEquals("key1", key); assertEquals("key1", key);
Assertions.assertEquals("value1", value); assertEquals("value1", value);
}); });
fifoCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3); fifoCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
@ -55,7 +60,7 @@ public class CacheTest {
for (int i = 0; i < RandomUtil.randomInt(100, 1000); i++) { for (int i = 0; i < RandomUtil.randomInt(100, 1000); i++) {
fifoCache.put("key" + i, "value" + i); fifoCache.put("key" + i, "value" + i);
} }
Assertions.assertEquals(100, fifoCache.size()); assertEquals(100, fifoCache.size());
} }
@Test @Test
@ -121,20 +126,42 @@ public class CacheTest {
final String value1 = timedCache.get("key1"); final String value1 = timedCache.get("key1");
Assertions.assertNull(value1); Assertions.assertNull(value1);
final String value2 = timedCache.get("key2"); final String value2 = timedCache.get("key2");
Assertions.assertEquals("value2", value2); assertEquals("value2", value2);
//5毫秒后由于设置了默认过期key3只被保留4毫秒因此为null //5毫秒后由于设置了默认过期key3只被保留4毫秒因此为null
final String value3 = timedCache.get("key3"); final String value3 = timedCache.get("key3");
Assertions.assertNull(value3); Assertions.assertNull(value3);
final String value3Supplier = timedCache.get("key3", () -> "Default supplier"); final String value3Supplier = timedCache.get("key3", () -> "Default supplier");
Assertions.assertEquals("Default supplier", value3Supplier); assertEquals("Default supplier", value3Supplier);
// 永不过期 // 永不过期
final String value4 = timedCache.get("key4"); final String value4 = timedCache.get("key4");
Assertions.assertEquals("value4", value4); assertEquals("value4", value4);
//取消定时清理 //取消定时清理
timedCache.cancelPruneSchedule(); timedCache.cancelPruneSchedule();
} }
/**
* TimedCache的数据过期后不是每次都触发监听器onRemove而是偶尔触发onRemove
* https://gitee.com/chinabugotech/hutool/issues/IBP752
*/
@Test
public void whenContainsKeyTimeout_shouldCallOnRemove() {
final int timeout = 50;
final TimedCache<Integer, String> ALARM_CACHE = new TimedCache<>(timeout);
final AtomicInteger counter = new AtomicInteger(0);
ALARM_CACHE.setListener((key, value) -> {
counter.incrementAndGet();
});
ALARM_CACHE.put(1, "value1");
ThreadUtil.sleep(100);
assertFalse(ALARM_CACHE.containsKey(1));
assertEquals(1, counter.get());
}
} }