mirror of
				https://github.com/LamGC/ContentGrabbingJi.git
				synced 2025-11-04 02:26:57 +00:00 
			
		
		
		
	[Add] 增加自动清理机制;
[Add] AutoCleanTimer, Cleanable 增加定时清理器和所需实现的接口; [Update] HashCacheStore 实现了 Cleanable 接口, 并使用了一种简单但效率较低的遍历清除方法, 有待改进;
This commit is contained in:
		@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					package net.lamgc.cgj.bot.cache.local;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.common.base.Throwables;
 | 
				
			||||||
 | 
					import com.google.common.util.concurrent.ThreadFactoryBuilder;
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 定时清理机制.
 | 
				
			||||||
 | 
					 * <p>定时通知已实现 {@link Cleanable} 接口的对象进行清理.
 | 
				
			||||||
 | 
					 * @see Cleanable
 | 
				
			||||||
 | 
					 * @author LamGC
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class AutoCleanTimer implements Runnable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final static Set<Cleanable> CLEANABLE_STORE_SET = new CopyOnWriteArraySet<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final static ScheduledExecutorService SCHEDULED_EXECUTOR =
 | 
				
			||||||
 | 
					            new ScheduledThreadPoolExecutor(1,
 | 
				
			||||||
 | 
					                    new ThreadFactoryBuilder()
 | 
				
			||||||
 | 
					                            .setDaemon(true)
 | 
				
			||||||
 | 
					                            .setNameFormat("Thread-AutoClean-%d")
 | 
				
			||||||
 | 
					                            .build()
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 是否启用调试模式.
 | 
				
			||||||
 | 
					     * <p>启用后将会打印相关日志.
 | 
				
			||||||
 | 
					     * @param enable 是否启用调试模式.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static void setDebugEnable(boolean enable) {
 | 
				
			||||||
 | 
					        DEBUG_ENABLE.set(enable);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 增加需要定时执行清理的缓存库
 | 
				
			||||||
 | 
					     * @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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private AutoCleanTimer() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void run() {
 | 
				
			||||||
 | 
					        if (CLEANABLE_STORE_SET.size() == 0) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CLEANABLE_STORE_SET.forEach(cleanable -> {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                cleanable.clean();
 | 
				
			||||||
 | 
					            } catch (Exception e) {
 | 
				
			||||||
 | 
					                log.error("{} 执行清理动作时发生异常:\n{}", cleanable.toString(), Throwables.getStackTraceAsString(e));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								ContentGrabbingJi-CacheStore-local/src/main/java/net/lamgc/cgj/bot/cache/local/Cleanable.java
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								ContentGrabbingJi-CacheStore-local/src/main/java/net/lamgc/cgj/bot/cache/local/Cleanable.java
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					package net.lamgc.cgj.bot.cache.local;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 可清理接口, 实现该接口代表该类具有清理动作.
 | 
				
			||||||
 | 
					 * @author LamGC
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public interface Cleanable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 该方法需要CacheStore完成对过期Entry的清除.
 | 
				
			||||||
 | 
					     * @return 返回已清理数量.
 | 
				
			||||||
 | 
					     * @throws Exception 即使该方法抛出异常, 也不会影响后续情况.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    long clean() throws Exception;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -20,6 +20,7 @@ package net.lamgc.cgj.bot.cache.local;
 | 
				
			|||||||
import net.lamgc.cgj.bot.cache.CacheStore;
 | 
					import net.lamgc.cgj.bot.cache.CacheStore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
 | 
					import java.util.concurrent.atomic.AtomicLong;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 基于 {@link Hashtable} 的缓存存储容器.
 | 
					 * 基于 {@link Hashtable} 的缓存存储容器.
 | 
				
			||||||
@ -28,7 +29,7 @@ import java.util.*;
 | 
				
			|||||||
 * @see net.lamgc.cgj.bot.cache.CacheStore
 | 
					 * @see net.lamgc.cgj.bot.cache.CacheStore
 | 
				
			||||||
 * @see Hashtable
 | 
					 * @see Hashtable
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class HashCacheStore<V> implements CacheStore<V> {
 | 
					public abstract class HashCacheStore<V> implements CacheStore<V>, Cleanable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final Map<String, CacheItem<V>> cacheMap = new Hashtable<>();
 | 
					    private final Map<String, CacheItem<V>> cacheMap = new Hashtable<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -100,6 +101,22 @@ public abstract class HashCacheStore<V> implements CacheStore<V> {
 | 
				
			|||||||
        return Collections.unmodifiableSet(cacheMap.keySet());
 | 
					        return Collections.unmodifiableSet(cacheMap.keySet());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public long clean() {
 | 
				
			||||||
 | 
					        Map<String, CacheItem<V>> cacheMap = getCacheMap();
 | 
				
			||||||
 | 
					        Date currentDate = new Date();
 | 
				
			||||||
 | 
					        AtomicLong cleanCount = new AtomicLong(0);
 | 
				
			||||||
 | 
					        cacheMap.keySet().removeIf(key -> {
 | 
				
			||||||
 | 
					            CacheItem<V> item = cacheMap.get(key);
 | 
				
			||||||
 | 
					            if (item != null && item.isExpire(currentDate)) {
 | 
				
			||||||
 | 
					                cleanCount.incrementAndGet();
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return cleanCount.get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 缓存项.
 | 
					     * 缓存项.
 | 
				
			||||||
     * @author LamGC
 | 
					     * @author LamGC
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user