mirror of
https://github.com/LamGC/ContentGrabbingJi.git
synced 2025-04-30 06:37:36 +00:00
[Fix] CacheStore-Local 修复 AutoCleanTimer 因逻辑错误未能及时轮询清理 Cleanable 的问题;
[Fix] AutoCleanTimer 调整 'run()' 方法, 修复轮询执行错误并改善无效 Cleanable Reference 的清除方式; Bug Description: 当发现 Reference 的指向为 null 时, 在收集了该对象后将会直接 return 导致后续轮询结束.
This commit is contained in:
parent
afd09968ac
commit
10fffca8b2
@ -5,14 +5,12 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.lang.ref.ReferenceQueue;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定时清理机制.
|
* 定时清理机制.
|
||||||
@ -34,37 +32,63 @@ public class AutoCleanTimer implements Runnable {
|
|||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(AutoCleanTimer.class);
|
private final static Logger log = LoggerFactory.getLogger(AutoCleanTimer.class);
|
||||||
|
|
||||||
|
private final static AtomicReference<ReferenceQueue<Cleanable>> REFERENCE_QUEUE = new AtomicReference<>(null);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
SCHEDULED_EXECUTOR.scheduleAtFixedRate(new AutoCleanTimer(), 100L, 100L, TimeUnit.MILLISECONDS);
|
SCHEDULED_EXECUTOR.scheduleAtFixedRate(new AutoCleanTimer(), 100L, 100L, TimeUnit.MILLISECONDS);
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(SCHEDULED_EXECUTOR::shutdownNow, "ShutdownThread-AutoClean"));
|
Runtime.getRuntime().addShutdownHook(new Thread(SCHEDULED_EXECUTOR::shutdownNow, "ShutdownThread-AutoClean"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加需要定时执行清理的缓存库
|
* 增加需要定时执行清理的缓存库.
|
||||||
* @param store 已实现Cleanable的对象
|
* @param store 已实现Cleanable的对象
|
||||||
*/
|
*/
|
||||||
public static void add(Cleanable store) {
|
public static void add(Cleanable store) {
|
||||||
CLEANABLE_STORE_SET.add(new WeakReference<>(store));
|
CLEANABLE_STORE_SET.add(new WeakReference<>(store, REFERENCE_QUEUE.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除对指定 Cleanable 的轮询.
|
||||||
|
* @param store 欲停止轮询的 Cleanable 对象.
|
||||||
|
*/
|
||||||
|
public static void remove(final Cleanable store) {
|
||||||
|
CLEANABLE_STORE_SET.removeIf(cleanableReference -> cleanableReference.get() == store);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前被轮询的 Cleanable 数量.
|
||||||
|
* @return 返回轮询的 Cleanable 数量.
|
||||||
|
*/
|
||||||
|
public static int size() {
|
||||||
|
return CLEANABLE_STORE_SET.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置虚引用回收队列, 以检查虚引用对象回收状况.
|
||||||
|
* <p> 本方法用于诊断 AutoCleanTimer 对虚引用对象的处理情况, 一般情况下无需使用.
|
||||||
|
* @param queue 引用队列.
|
||||||
|
*/
|
||||||
|
public static void setWeakReferenceQueue(ReferenceQueue<Cleanable> queue) {
|
||||||
|
REFERENCE_QUEUE.set(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AutoCleanTimer() {}
|
private AutoCleanTimer() {}
|
||||||
|
|
||||||
|
private final Set<WeakReference<Cleanable>> toBeCleanReference = new HashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (CLEANABLE_STORE_SET.size() == 0) {
|
if (CLEANABLE_STORE_SET.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<WeakReference<Cleanable>> iterator = CLEANABLE_STORE_SET.iterator();
|
for (WeakReference<Cleanable> reference : CLEANABLE_STORE_SET) {
|
||||||
Set<WeakReference<Cleanable>> toBeCleanReference = new HashSet<>();
|
|
||||||
while(iterator.hasNext()) {
|
|
||||||
WeakReference<Cleanable> reference = iterator.next();
|
|
||||||
Cleanable store = reference.get();
|
Cleanable store = reference.get();
|
||||||
if (store == null) {
|
if (reference.isEnqueued() || store == null) {
|
||||||
// 由于 COW ArraySet 的 Iterator 不支持 remove 操作,
|
// 由于 COW ArraySet 的 Iterator 不支持 remove 操作,
|
||||||
// 所以先收集起来, 等完成所有清理工作后统一删除引用.
|
// 所以先收集起来, 等完成所有清理工作后统一删除引用.
|
||||||
toBeCleanReference.add(reference);
|
toBeCleanReference.add(reference);
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
store.clean();
|
store.clean();
|
||||||
@ -72,6 +96,10 @@ public class AutoCleanTimer implements Runnable {
|
|||||||
log.error("{} 执行清理动作时发生异常:\n{}", store.toString(), Throwables.getStackTraceAsString(e));
|
log.error("{} 执行清理动作时发生异常:\n{}", store.toString(), Throwables.getStackTraceAsString(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toBeCleanReference.size() != 0) {
|
||||||
CLEANABLE_STORE_SET.removeAll(toBeCleanReference);
|
CLEANABLE_STORE_SET.removeAll(toBeCleanReference);
|
||||||
|
toBeCleanReference.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user