/* ================================================================== * Created [2009-4-27 下午11:32:55] by Jon.King * ================================================================== * TSS * ================================================================== * mailTo:jinpujun@hotmail.com * Copyright (c) Jon.King, 2009-2012 * ================================================================== */ package com.jinhe.tss.core.cachepool; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.log4j.Logger; import com.jinhe.tss.core.cachepool.container.IPoolContainer; import com.jinhe.tss.core.cachepool.strategy.CacheStrategy; import com.jinhe.tss.core.exception.BusinessException; /** * <p> AbstractPool.java </p> * * 对象池抽象类,定义通用的方法。 * * @author Jon.King 2007-1-3 * */ public abstract class AbstractPool implements IPool { protected Logger log = Logger.getLogger(this.getClass()); // 对象池属性 protected long requests; // 请求数 protected long hits; // 命中数 protected boolean released = false; // 是否已释放 protected boolean asyncDestroy = false; // 是否异步销毁 protected ICacheLoader loader; // 缓存项载入类 protected IArithmetic arithmetic; // 缓存算法类 protected CacheStrategy strategy; // 缓存策略 protected Set<IPoolListener> listeners = new HashSet<IPoolListener> (); // 监听器列表 public abstract void init(); public abstract int getSize(); public abstract void release(boolean forced) ; public abstract IPoolContainer getFree(); public abstract IPoolContainer getUsing(); public Cacheable getObject(Object key) { if(key == null) { return null; } Cacheable item = getOldObject(key); addRequests(); if(item != null){ addHits(); item.addHit(); item.updateAccessed(); } else { //调用ICacheLoader来载入需要的缓存项,取到则放入缓存池中 item = reload(new TimeWrapper(key, null)); if(item != null) { putObject(item.getKey(), item.getValue()); } } return item; } public Cacheable getOldObject(Object key) { if (released) { log.error("缓存池(" + this.getName() + ")已经被释放!"); } return getFree().get(key) == null ? getUsing().get(key) : getFree().get(key); } public Cacheable putObject(Object key, Object value) { if(key == null) { return null; } Cacheable oldItem = getOldObject(key); if(oldItem != null){ oldItem.update(value); return oldItem; }else{ //缓存项放入缓存池的同时也设置了其生命周期 Cacheable newItem = getFree().put(key, new TimeWrapper(key, value, strategy.getCyclelife())); firePoolEvent(ObjectPoolEvent.PUT_IN);//事件监听器将唤醒所有等待中的线程,包括cleaner线程,checkout,remove等操作的等待线程 return newItem; } } public Cacheable removeObject(Object key) { Cacheable item = getFree().remove(key); firePoolEvent(ObjectPoolEvent.REMOVE); return item; } public List<Cacheable> listItems() { Set<Cacheable> values = new HashSet<Cacheable>(); if(getFree() != null) { values.addAll(getFree().getValues()); } if(getUsing() != null) { values.addAll(getUsing().getValues()); } return new ArrayList<Cacheable>(values); } public List<CacheableKey> listKeys() { Set<CacheableKey> keys = new HashSet<CacheableKey>(); if(getFree() != null) { keys.addAll(getFree().getKeys()); } if(getUsing() != null) { keys.addAll(getUsing().getKeys()); } return new ArrayList<CacheableKey>(keys); } public void flush() { release(true); resetHitCounter(); log.debug("已经清除池中所有的缓存项。"); } public Cacheable reload(final Cacheable obj) throws RuntimeException { Cacheable newObj = loader.reloadCacheObject(obj); //如果重新加载的缓存项为空,则将原先的缓存项从缓存池中移除,否则则覆盖原有的缓存项。 if(newObj == null) removeObject(obj.getKey()); else newObj = putObject(newObj.getKey(), newObj.getValue()); return newObj; } /** * 销毁指定对象(如果有必要的话可采用异步); */ public void destroyObject(final Cacheable o) { if (o == null) return; if (isAsyncDestroy()){ Thread t = new Thread(new Runnable(){ public void run() { arithmetic.destroy(o); } }); t.start(); }else arithmetic.destroy(o); } public final void releaseAsync(final boolean forced) { Thread t = new Thread(new Runnable(){ public void run() { release(forced); } }); t.start(); } public CacheStrategy getCacheStrategy() { return this.strategy; } public void setCacheStrategy(CacheStrategy strategy) { //判断是否是修改缓存策略还是在初始化缓存池,初始化的话strategy为null if(this.getCacheStrategy() != null) this.strategy.fireEventIfChanged(strategy);//缓存策略改变则触发事件 else this.strategy = strategy; } public void setArithmetic(IArithmetic arithmetic) { this.arithmetic = arithmetic; } public void setLoader(ICacheLoader loader) { this.loader = loader; } public IArithmetic getArithmetic(){ return this.arithmetic; } public String getName() { return getCacheStrategy().getName(); } public long getRequests() { return requests; } protected void addRequests() { requests++; } protected void addHits() { hits++; } /** * 重置请求数和点击数 * requests = hits = 0 */ protected final void resetHitCounter() { requests = hits = 0; } public final float getHitRate() { return (requests == 0) ? 0 : (((float) hits / requests) * 100f); } public final void setAsyncDestroy(boolean b) { asyncDestroy = b; } public final boolean isAsyncDestroy() { return asyncDestroy; } public final boolean isReleased() { return this.released; } public final void firePoolEvent(int eventType) { if (listeners.isEmpty()) return; ObjectPoolEvent poolEvent = new ObjectPoolEvent(this, eventType); for (Iterator<IPoolListener> iter = listeners.iterator(); iter.hasNext();){ (iter.next()).dealwithPoolEvent(poolEvent); } } public final void addObjectPoolListener(IPoolListener x){ listeners.add(x); } public final void removeObjectPoolListener(IPoolListener x){ listeners.remove(x); } protected Cacheable checkOut() { Cacheable item = getFree().getByAccessMethod(getCacheStrategy().getAccessMethod()); if(item != null){ item.addHit(); getFree().remove(item.getKey()); getUsing().put(item.getKey(), item); } return item; } public Cacheable checkOut(long timeout) { if(timeout <= 0) { timeout = this.getCacheStrategy().getInterruptTime(); } long time = System.currentTimeMillis(); Cacheable o = null; o = checkOut(); synchronized(this){ while (o == null && (System.currentTimeMillis() - time < timeout)) { try { log.debug("缓存池(" + this.getName() + ")中没有可用的缓存项......等待 " + timeout + "(毫秒)"); wait(timeout); o = checkOut(); }catch (InterruptedException e) { log.error("检出时等待被中断", e); } } } if(o == null){ String errorMsg = "缓存池(" + this.getName() + ")已满,且各缓存项都处于使用状态,需要等待。可考虑重新设置缓存策略!"; log.error(errorMsg); throw new BusinessException(errorMsg); } return o; } public void checkIn(Cacheable o) { if (o == null){ log.error("试图返回空的缓存项"); return; } //判断对象是否存在using池中,是的话将对象从using池中移出,否则抛出异常 if(!o.equals(getUsing().remove(o.getKey()))){ log.error("试图返回不是using池中对象到free中,返回失败! " + getName()); throw new BusinessException("试图返回不是using池中对象到free中,返回失败! " + getName()); } Object value = o.getValue(); //如果池已满,则销毁对象,否则则放回池中 int maxSize = getCacheStrategy().getPoolSize().intValue(); if (maxSize > 0 && getSize() >= maxSize){ destroyObject(o); }else{ try{ // 如果对象实现了Reusable接口,则执行重置操作 if(value instanceof Reusable) { ((Reusable)value).recycle(); } getFree().put(o.getKey(), o); //重新放入free池中,其点击率等属性已改变 firePoolEvent(ObjectPoolEvent.CHECKIN);//事件监听器将唤醒所有等待中的线程,包括cleaner线程,checkout,remove等操作的等待线程 log.debug(o.getValue() + " 缓存项已经回收!"); }catch (Exception e){ destroyObject(o); // 如果不能回收则销毁 log.error("无法回收缓存项,已销毁!", e); } } } public Cacheable remove() { Cacheable o = getFree().getByAccessMethod(getCacheStrategy().getAccessMethod().intValue()); //如果free池中取不到,则要等using池中的缓存对象返回到free中。线程等待 long timeout = getCacheStrategy().getInterruptTime().longValue(); long time = System.currentTimeMillis(); synchronized(this){ while (o == null && (System.currentTimeMillis() - time < timeout)) { try { log.debug("free缓存池(" + this.getName() + ")中没有可用的项......等待 " + timeout + "ms"); wait(timeout); o = checkOut(); }catch (InterruptedException e) { log.error("等待移除 checkIn 对象时等待被中断", e); } } } removeObject(o.getKey()); return o; } public boolean purge() { log.debug("开始清除 (\"" + this.getName() + "\") 池中过期的缓存项 ....... "); int count = 0; Cacheable item = null; for (CacheableKey key : getFree().getKeys()){ item = getFree().get(key); if (item != null && item.isExpired()){ removeObject(item.getKey()); destroyObject(item); count++; } } log.debug("共清除了 (\"" + this.getName() + "\") 池中 " + count + " 个缓存对象。"); return getFree().size() > 0 || count > 0; } }