diff --git a/ContentGrabbingJi-CacheStore-local/src/main/java/net/lamgc/cgj/bot/cache/local/AutoCleanTimer.java b/ContentGrabbingJi-CacheStore-local/src/main/java/net/lamgc/cgj/bot/cache/local/AutoCleanTimer.java index e0c2dc9..4019c4a 100644 --- a/ContentGrabbingJi-CacheStore-local/src/main/java/net/lamgc/cgj/bot/cache/local/AutoCleanTimer.java +++ b/ContentGrabbingJi-CacheStore-local/src/main/java/net/lamgc/cgj/bot/cache/local/AutoCleanTimer.java @@ -5,12 +5,14 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.Iterator; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; /** * 定时清理机制. @@ -20,7 +22,7 @@ import java.util.concurrent.atomic.AtomicBoolean; */ public class AutoCleanTimer implements Runnable { - private final static Set CLEANABLE_STORE_SET = new CopyOnWriteArraySet<>(); + private final static Set> CLEANABLE_STORE_SET = new CopyOnWriteArraySet<>(); private final static ScheduledExecutorService SCHEDULED_EXECUTOR = new ScheduledThreadPoolExecutor(1, @@ -32,22 +34,9 @@ public class AutoCleanTimer implements Runnable { private final static Logger log = LoggerFactory.getLogger(AutoCleanTimer.class); - private final static AtomicBoolean DEBUG_ENABLE = new AtomicBoolean(false); - static { SCHEDULED_EXECUTOR.scheduleAtFixedRate(new AutoCleanTimer(), 100L, 100L, TimeUnit.MILLISECONDS); - Thread shutdownHook = new Thread(SCHEDULED_EXECUTOR::shutdown); - shutdownHook.setName("ShutdownThread-AutoClean"); - Runtime.getRuntime().addShutdownHook(shutdownHook); - } - - /** - * 是否启用调试模式. - *

启用后将会打印相关日志. - * @param enable 是否启用调试模式. - */ - public static void setDebugEnable(boolean enable) { - DEBUG_ENABLE.set(enable); + Runtime.getRuntime().addShutdownHook(new Thread(SCHEDULED_EXECUTOR::shutdownNow, "ShutdownThread-AutoClean")); } /** @@ -55,15 +44,7 @@ public class AutoCleanTimer implements Runnable { * @param store 已实现Cleanable的对象 */ public static void add(Cleanable store) { - CLEANABLE_STORE_SET.add(store); - } - - /** - * 移除已添加的缓存库 - * @param store 需要从AutoCleanTimer移除的对象 - */ - public static void remove(Cleanable store) { - CLEANABLE_STORE_SET.remove(store); + CLEANABLE_STORE_SET.add(new WeakReference<>(store)); } private AutoCleanTimer() {} @@ -74,12 +55,23 @@ public class AutoCleanTimer implements Runnable { return; } - CLEANABLE_STORE_SET.forEach(cleanable -> { - try { - cleanable.clean(); - } catch (Exception e) { - log.error("{} 执行清理动作时发生异常:\n{}", cleanable.toString(), Throwables.getStackTraceAsString(e)); + Iterator> iterator = CLEANABLE_STORE_SET.iterator(); + Set> toBeCleanReference = new HashSet<>(); + while(iterator.hasNext()) { + WeakReference reference = iterator.next(); + Cleanable store = reference.get(); + if (store == null) { + // 由于 COW ArraySet 的 Iterator 不支持 remove 操作, + // 所以先收集起来, 等完成所有清理工作后统一删除引用. + toBeCleanReference.add(reference); + return; } - }); + try { + store.clean(); + } catch (Exception e) { + log.error("{} 执行清理动作时发生异常:\n{}", store.toString(), Throwables.getStackTraceAsString(e)); + } + } + CLEANABLE_STORE_SET.removeAll(toBeCleanReference); } }