mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add TimedReentrantCache
This commit is contained in:
parent
7d1438b665
commit
35505dfbf8
@ -111,7 +111,7 @@ public abstract class StampedCache<K, V> extends AbstractCache<K, V> {
|
||||
* <pre>
|
||||
* 1. 读取时无写入,不冲突,直接获取值
|
||||
* 2. 读取时无写入,但是乐观读时触发了并发异常,此时获取同步锁,获取新值
|
||||
* 4. 读取时有写入,此时获取同步锁,获取新值
|
||||
* 3. 读取时有写入,此时获取同步锁,获取新值
|
||||
* </pre>
|
||||
*
|
||||
* @param key 键
|
||||
|
@ -17,16 +17,16 @@
|
||||
package org.dromara.hutool.core.cache.impl;
|
||||
|
||||
import org.dromara.hutool.core.cache.GlobalPruneTimer;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.lang.mutable.Mutable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
/**
|
||||
* 定时缓存<br>
|
||||
* 此缓存没有容量限制,对象只有在过期后才会被移除
|
||||
* 此缓存没有容量限制,对象只有在过期后才会被移除<br>
|
||||
* 此缓存采用读写乐观锁,用于可脏读的场景,不能使用LinkedHashMap
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
@ -57,7 +57,7 @@ public class TimedCache<K, V> extends StampedCache<K, V> {
|
||||
public TimedCache(final long timeout, final Map<Mutable<K>, CacheObj<K, V>> map) {
|
||||
this.capacity = 0;
|
||||
this.timeout = timeout;
|
||||
this.cacheMap = map;
|
||||
this.cacheMap = Assert.isNotInstanceOf(LinkedHashMap.class, map);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- prune
|
||||
|
106
hutool-core/src/main/java/org/dromara/hutool/core/cache/impl/TimedReentrantCache.java
vendored
Normal file
106
hutool-core/src/main/java/org/dromara/hutool/core/cache/impl/TimedReentrantCache.java
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.cache.impl;
|
||||
|
||||
import org.dromara.hutool.core.cache.GlobalPruneTimer;
|
||||
import org.dromara.hutool.core.lang.mutable.Mutable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
/**
|
||||
* 定时缓存<br>
|
||||
* 此缓存没有容量限制,对象只有在过期后才会被移除
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
*/
|
||||
public class TimedReentrantCache<K, V> extends ReentrantCache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 正在执行的定时任务 */
|
||||
private ScheduledFuture<?> pruneJobFuture;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param timeout 超时(过期)时长,单位毫秒
|
||||
*/
|
||||
public TimedReentrantCache(final long timeout) {
|
||||
this(timeout, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param timeout 过期时长
|
||||
* @param map 存储缓存对象的map
|
||||
*/
|
||||
public TimedReentrantCache(final long timeout, final Map<Mutable<K>, CacheObj<K, V>> map) {
|
||||
this.capacity = 0;
|
||||
this.timeout = timeout;
|
||||
this.cacheMap = map;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- prune
|
||||
/**
|
||||
* 清理过期对象
|
||||
*
|
||||
* @return 清理数
|
||||
*/
|
||||
@Override
|
||||
protected int pruneCache() {
|
||||
int count = 0;
|
||||
final Iterator<CacheObj<K, V>> values = cacheObjIter();
|
||||
CacheObj<K, V> co;
|
||||
while (values.hasNext()) {
|
||||
co = values.next();
|
||||
if (co.isExpired()) {
|
||||
values.remove();
|
||||
onRemove(co.key, co.obj);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- auto prune
|
||||
/**
|
||||
* 定时清理
|
||||
*
|
||||
* @param delay 间隔时长,单位毫秒
|
||||
* @return this
|
||||
*/
|
||||
public TimedReentrantCache<K, V> schedulePrune(final long delay) {
|
||||
this.pruneJobFuture = GlobalPruneTimer.INSTANCE.schedule(this::prune, delay);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消定时清理
|
||||
*/
|
||||
public void cancelPruneSchedule() {
|
||||
if (null != pruneJobFuture) {
|
||||
pruneJobFuture.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -22,6 +22,8 @@ import org.dromara.hutool.core.lang.mutable.Mutable;
|
||||
import org.dromara.hutool.core.lang.ref.Ref;
|
||||
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* 弱引用缓存<br>
|
||||
* 对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。<br>
|
||||
@ -42,7 +44,7 @@ public class WeakCache<K, V> extends TimedCache<K, V>{
|
||||
* @param timeout 超时时常,单位毫秒,-1或0表示无限制
|
||||
*/
|
||||
public WeakCache(final long timeout) {
|
||||
super(timeout, new WeakConcurrentMap<>());
|
||||
super(timeout, new WeakHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1989,7 +1989,7 @@ public class CollUtil {
|
||||
* @param consumer {@link SerBiConsumer} 遍历的每条数据处理器
|
||||
*/
|
||||
public static <T> void forEach(final Iterator<T> iterator, final SerBiConsumer<Integer, T> consumer) {
|
||||
IterUtil.forEach(iterator, consumer);
|
||||
IterUtil.indexForEach(iterator, consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -910,7 +910,7 @@ public class IterUtil {
|
||||
* @param iterator {@link Iterator}
|
||||
* @param consumer {@link SerBiConsumer} 遍历的每条数据处理器
|
||||
*/
|
||||
public static <T> void forEach(final Iterator<T> iterator, final SerBiConsumer<Integer, T> consumer) {
|
||||
public static <T> void indexForEach(final Iterator<T> iterator, final SerBiConsumer<Integer, T> consumer) {
|
||||
if (iterator == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -173,9 +173,7 @@ public class DateBetween implements Serializable {
|
||||
|
||||
endCal.set(Calendar.YEAR, beginCal.get(Calendar.YEAR));
|
||||
final long between = endCal.getTimeInMillis() - beginCal.getTimeInMillis();
|
||||
if (between < 0) {
|
||||
return result - 1;
|
||||
}
|
||||
return between < 0 ? result - 1 : result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -563,6 +563,7 @@ public class Assert {
|
||||
// endregion
|
||||
|
||||
// region ----- notContain
|
||||
|
||||
/**
|
||||
* 断言给定字符串是否不被另一个字符串包含(即是否为子串),并使用指定的函数获取错误信息返回<br>
|
||||
* 如果非子串,返回子串,如果是子串,则抛出{@link IllegalArgumentException}异常。
|
||||
@ -689,7 +690,8 @@ public class Assert {
|
||||
// region ----- isInstanceOf and isAssignable
|
||||
|
||||
/**
|
||||
* 断言给定对象是否是给定类的实例
|
||||
* 断言给定对象是否是给定类的实例,如果不是则抛出异常<br>
|
||||
* 此方法用于限定对象的类型
|
||||
* <pre class="code">
|
||||
* Assert.instanceOf(Foo.class, foo);
|
||||
* </pre>
|
||||
@ -706,7 +708,8 @@ public class Assert {
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言给定对象是否是给定类的实例
|
||||
* 断言给定对象是否是给定类的实例<br>
|
||||
* 此方法用于限定对象的类型
|
||||
* <pre class="code">
|
||||
* Assert.instanceOf(Foo.class, foo, "foo must be an instance of class Foo");
|
||||
* </pre>
|
||||
@ -728,6 +731,48 @@ public class Assert {
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言给定对象不是否是给定类的实例,如果是则抛出异常<br>
|
||||
* 此方法用于排除给定类型
|
||||
* <pre class="code">
|
||||
* Assert.isNotInstanceOf(Foo.class, foo);
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> 被检查对象泛型类型
|
||||
* @param type 被检查对象匹配的类型
|
||||
* @param obj 被检查对象
|
||||
* @return 被检查的对象
|
||||
* @throws IllegalArgumentException if the object is not an instance of clazz
|
||||
* @see Class#isInstance(Object)
|
||||
*/
|
||||
public static <T> T isNotInstanceOf(final Class<?> type, final T obj) {
|
||||
return isNotInstanceOf(type, obj, "Object [{}] must be not instanceof [{}]", obj, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言给定对象是否不是给定类的实例,如果是则抛出异常<br>
|
||||
* 此方法用于排除给定类型
|
||||
* <pre class="code">
|
||||
* Assert.isNotInstanceOf(Foo.class, foo, "foo must be not an Foo");
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> 被检查对象泛型类型
|
||||
* @param type 被检查对象匹配的类型
|
||||
* @param obj 被检查对象
|
||||
* @param errorMsgTemplate 异常时的消息模板
|
||||
* @param params 参数列表
|
||||
* @return 被检查对象
|
||||
* @throws IllegalArgumentException if the object is an instance of clazz
|
||||
* @see Class#isInstance(Object)
|
||||
*/
|
||||
public static <T> T isNotInstanceOf(final Class<?> type, final T obj, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
|
||||
notNull(type, "Type to check against must not be null");
|
||||
if (type.isInstance(obj)) {
|
||||
throw new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言 {@code superType.isAssignableFrom(subType)} 是否为 {@code true}.
|
||||
* <pre class="code">
|
||||
@ -816,6 +861,7 @@ public class Assert {
|
||||
// endregion
|
||||
|
||||
// region ----- checkIndex
|
||||
|
||||
/**
|
||||
* 检查下标(数组、集合、字符串)是否符合要求,下标必须满足:
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user