package com.jarvis.cache; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jarvis.cache.annotation.Cache; import com.jarvis.cache.aop.CacheAopProxyChain; import com.jarvis.cache.to.AutoLoadConfig; import com.jarvis.cache.to.CacheKeyTO; import com.jarvis.cache.to.CacheWrapper; public class RefreshHandler { private static final Logger logger=LoggerFactory.getLogger(RefreshHandler.class); /** * 刷新缓存线程池 */ private final ThreadPoolExecutor refreshThreadPool; /** * 正在刷新缓存队列 */ private final ConcurrentHashMap<CacheKeyTO, Byte> refreshing; private final AbstractCacheManager cacheManager; public RefreshHandler(AbstractCacheManager cacheManager, AutoLoadConfig config) { this.cacheManager=cacheManager; int corePoolSize=config.getRefreshThreadPoolSize();// 线程池的基本大小 int maximumPoolSize=config.getRefreshThreadPoolMaxSize();// 线程池最大大小,线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。 int keepAliveTime=config.getRefreshThreadPoolkeepAliveTime(); TimeUnit unit=TimeUnit.MINUTES; int queueCapacity=config.getRefreshQueueCapacity();// 队列容量 refreshing=new ConcurrentHashMap<CacheKeyTO, Byte>(queueCapacity); LinkedBlockingQueue<Runnable> queue=new LinkedBlockingQueue<Runnable>(queueCapacity); RejectedExecutionHandler rejectedHandler=new RefreshRejectedExecutionHandler(); refreshThreadPool=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, queue, new ThreadFactory() { private final AtomicInteger threadNumber=new AtomicInteger(1); private final String namePrefix="autoload-cache-RefreshHandler-"; @Override public Thread newThread(Runnable r) { Thread t=new Thread(r, namePrefix + threadNumber.getAndIncrement()); t.setDaemon(true); return t; } }, rejectedHandler); } public void doRefresh(CacheAopProxyChain pjp, Cache cache, CacheKeyTO cacheKey, CacheWrapper<Object> cacheWrapper) { int expire=cacheWrapper.getExpire(); if(expire < 60) {// 如果过期时间太小了,就不允许自动加载,避免加载过于频繁,影响系统稳定性 return; } // 计算超时时间 int alarmTime=cache.alarmTime(); long timeout; if(alarmTime > 0 && alarmTime < expire) { timeout=expire - alarmTime; } else { if(expire >= 600) { timeout=expire - 120; } else { timeout=expire - 60; } } if((System.currentTimeMillis() - cacheWrapper.getLastLoadTime()) < (timeout * 1000)) { return; } Byte tmpByte=refreshing.get(cacheKey); if(null != tmpByte) {// 如果有正在刷新的请求,则不处理 return; } tmpByte=1; if(null == refreshing.putIfAbsent(cacheKey, tmpByte)) { try { refreshThreadPool.execute(new RefreshTask(pjp, cache, cacheKey, cacheWrapper)); } catch(Exception e) { logger.error(e.getMessage(), e); } } } public void shutdown() { refreshThreadPool.shutdownNow(); try { refreshThreadPool.awaitTermination(5, TimeUnit.SECONDS); } catch(InterruptedException e) { e.printStackTrace(); } } class RefreshTask implements Runnable { private final CacheAopProxyChain pjp; private final Cache cache; private final CacheKeyTO cacheKey; private final CacheWrapper<Object> cacheWrapper; private final Object[] arguments; public RefreshTask(CacheAopProxyChain pjp, Cache cache, CacheKeyTO cacheKey, CacheWrapper<Object> cacheWrapper) throws Exception { this.pjp=pjp; this.cache=cache; this.cacheKey=cacheKey; this.cacheWrapper=cacheWrapper; this.arguments=(Object[])cacheManager.getCloner().deepCloneMethodArgs(pjp.getMethod(), pjp.getArgs()); // 进行深度复制(因为是异步执行,防止外部修改参数值) } @Override public void run() { DataLoaderFactory factory=DataLoaderFactory.getInstance(); DataLoader dataLoader=factory.getDataLoader(); CacheWrapper<Object> newCacheWrapper=null; try { newCacheWrapper=dataLoader.init(pjp, cacheKey, cache, cacheManager, arguments).loadData().getCacheWrapper(); } catch(Throwable ex) { logger.error(ex.getMessage(), ex); } boolean isFirst=dataLoader.isFirst(); factory.returnObject(dataLoader); if(isFirst) { if(null == newCacheWrapper && null != cacheWrapper) {// 如果加载失败,则把旧数据进行续租 int newExpire=cacheWrapper.getExpire() / 2; if(newExpire < 120) { newExpire=120; } newCacheWrapper=new CacheWrapper<Object>(cacheWrapper.getCacheObject(), newExpire); } try { if(null != newCacheWrapper) { cacheManager.writeCache(pjp, arguments, cache, cacheKey, newCacheWrapper); } } catch(Exception e) { logger.error(e.getMessage(), e); } } refreshing.remove(cacheKey); } public CacheKeyTO getCacheKey() { return cacheKey; } } class RefreshRejectedExecutionHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if(!e.isShutdown()) { Runnable last=e.getQueue().poll(); if(last instanceof RefreshTask) { RefreshTask lastTask=(RefreshTask)last; refreshing.remove(lastTask.getCacheKey()); } e.execute(r); } } } }