使用Hashtable和线程技术制作自己简单的内存缓存
1. 首先,我们要做一个缓存数据类
这个数据类要有一个数据成员,存放你的缓存数据,可以是一个类,也可以是一个List
我们这里把它统一为Object
然后要有一个过期时间,并且有一个访问次数,如果访问达到一定数量后,自动重置缓存
代码如下:
package zeus.cache.memory;public class CacheData {private Object data;private long time;private int count;public CacheData() {}public CacheData(Object data, long time, int count) {this.data = data;this.time = time;this.count = count;}public CacheData(Object data) {this.data = data;this.time = System.currentTimeMillis();this.count = 1;}public void addCount() {count++;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public long getTime() {return time;}public void setTime(long time) {this.time = time;}}public class CacheOperation {private static CacheOperation singleton = null;private Hashtable cacheMap;// 存放缓存数据private ArrayList threadKeys;// 处于线程更新中的key值列表public static CacheOperation getInstance() {if (singleton == null) {singleton = new CacheOperation();}return singleton;}private CacheOperation() {cacheMap = new Hashtable();threadKeys = new ArrayList();} ...}/** * 添加数据缓存 与方法getCacheData(String key, long intervalTime, int * maxVisitCount)配合使用 * * @param key * @param data */public void addCacheData(String key, Object data) {addCacheData(key, data, true);}private void addCacheData(String key, Object data, boolean check) {if (Runtime.getRuntime().freeMemory() < 5L * 1024L * 1024L) {// 虚拟机内存小于10兆,则清除缓存// log.warn("WEB缓存:内存不足,开始清空缓存!");removeAllCacheData();return;} else if (check && cacheMap.containsKey(key)) {// log.warn("WEB缓存:key值= " + key + " 在缓存中重复, 本次不缓存!");return;}cacheMap.put(key, new CacheData(data));}/** * 些类存放方法的主调对像,名称及参数数组 * * @author master haku * */public class MethodInfo {private Object o;private String methodName;private Object[] parameters;public MethodInfo(Object o, String methodName, Object[] parameters) {this.o = o;this.methodName = methodName;this.parameters = parameters;}public String getMethodName() {return methodName;}public void setMethodName(String methodName) {this.methodName = methodName;}public Object getO() {return o;}public void setO(Object o) {this.o = o;}public Object[] getParameters() {return parameters;}public void setParameters(Object[] parameters) {this.parameters = parameters;}public String toString() {StringBuffer str = new StringBuffer(methodName);if (parameters != null) {str.append("(");for (int i = 0; i < parameters.length; i++) {if (parameters[i] instanceof Object[]) {str.append(Arrays.toString((Object[]) parameters[i])).append(",");} else {str.append(parameters[i]).append(",");}}str.append(")");}return str.toString();}}/** * 线程调用方法 * * @author master haku * */private class InvokeThread extends Thread {private Object o;private String methodName;private Object[] parameters;private String key;public InvokeThread(Object o, String methodName, Object[] parameters,String key) {this.o = o;this.methodName = methodName;this.parameters = parameters;this.key = key;}public void run() {threadKeys.add(key);invoke(o, methodName, parameters, key);threadKeys.remove(key);}}/** * 找不到完全匹配的方法时,对参数进行向父类匹配 因为方法aa(java.util.List) 与 * aa(java.util.ArrayList)不能自动匹配到 * * @param oc * @param methodName * @param pcs * @return * @throws NoSuchMethodException * @throws NoSuchMethodException */private Method matchMethod(Class oc, String methodName, Class[] pcs)throws NoSuchMethodException, SecurityException {try {Method method = oc.getDeclaredMethod(methodName, pcs);return method;} catch (NoSuchMethodException e) {Method[] ms = oc.getDeclaredMethods();aa: for (int i = 0; i < ms.length; i++) {if (ms[i].getName().equals(methodName)) {Class[] pts = ms[i].getParameterTypes();if (pts.length == pcs.length) {for (int j = 0; j < pts.length; j++) {if (!pts[j].isAssignableFrom(pcs[j])) {break aa;}}return ms[i];}}}throw new NoSuchMethodException();}}/** * 递归调用给定方法更新缓存中数据据 * * @param o * @param methodName * @param parameters * @param key * @return 若反射调用方法返回值为空则返回该值的类型 */private Object invoke(Object o, String methodName, Object[] parameters,String key) {Object returnValue = null;try {Class[] pcs = null;if (parameters != null) {pcs = new Class[parameters.length];for (int i = 0; i < parameters.length; i++) {if (parameters[i] instanceof MethodInfo) {// 参数类型是MethodInfo则调用该方法的返回值做这参数MethodInfo pmi = (MethodInfo) parameters[i];Object pre = invoke(pmi.getO(), pmi.getMethodName(),pmi.getParameters(), null);parameters[i] = pre;}if (parameters[i] instanceof Class) {pcs[i] = (Class) parameters[i];parameters[i] = null;} else {pcs[i] = parameters[i].getClass();}}}Class oc = o instanceof Class ? (Class) o : o.getClass();// Method m = oc.getDeclaredMethod(methodName, pcs);Method m = matchMethod(oc, methodName, pcs);returnValue = m.invoke(o, parameters);if (key != null && returnValue != null) {addCacheData(key, returnValue, false);}if (returnValue == null) {returnValue = m.getReturnType();}} catch (Exception e) {// log.error("调用方法失败,methodName=" + methodName);if (key != null) {removeCacheData(key);// log.error("更新缓存失败,缓存key=" + key);}e.printStackTrace();}return returnValue;}/** * 当缓存中数据失效时,用不给定的方法线程更新数据 * * @param o * 取得数据的对像(该方法是静态方法是不用实例,则传Class实列) * @param methodName * 该对像中的方法 * @param parameters * 该方法的参数列表(参数列表中对像都要实现toString方法,若列表中某一参数为空则传它所属类的Class) * @param intervalTime * 缓存的时间周期,小于等于0时不限制 * @param maxVisitCount * 访问累积次数,小于等于0时不限制 * @return */public Object getCacheData(Object o, String methodName, Object[] parameters,long intervalTime, int maxVisitCount) {Class oc = o instanceof Class ? (Class) o : o.getClass();StringBuffer key = new StringBuffer(oc.getName());// 生成缓存key值key.append("-").append(methodName);if (parameters != null) {for (int i = 0; i < parameters.length; i++) {if (parameters[i] instanceof Object[]) {key.append("-").append(Arrays.toString((Object[]) parameters[i]));} else {key.append("-").append(parameters[i]);}}}CacheData cacheData = (CacheData) cacheMap.get(key.toString());if (cacheData == null) {// 等待加载并返回Object returnValue = invoke(o, methodName, parameters, key.toString());return returnValue instanceof Class ? null : returnValue;}if (intervalTime > 0&& (System.currentTimeMillis() - cacheData.getTime()) > intervalTime) {daemonInvoke(o, methodName, parameters, key.toString());// 缓存时间超时,启动线程更新数据} else if (maxVisitCount > 0 && (maxVisitCount - cacheData.getCount()) <= 0) {// 访问次数超出,启动线程更新数据daemonInvoke(o, methodName, parameters, key.toString());} else {cacheData.addCount();}return cacheData.getData();}/** * 移除缓存中的数据 * * @param key */public void removeCacheData(String key) {cacheMap.remove(key);}/** * 移除所有缓存中的数据 * */public void removeAllCacheData() {cacheMap.clear();}public class GtaHotelCacheService {public List<TGtahotel> getAllHotelList() {GtaHotelDao_Hib hotelDao = new GtaHotelDao_Hib();CacheOperation co = CacheOperation.getInstance();Object hotels = co.getCacheData(hotelDao, "getHotelList", new Object[]{}, 3600*1000, 0);return (List<TGtahotel>)hotels;}}public class ZeusCacheTest {public static void main(String[] args) {Scanner in;String key = "Y";PerformanceManager perf = null;while (key.toUpperCase().equals("Y")) {/* -- Performance Test Start -- */ perf = new PerformanceManager("Gta Hotel From Cache", new TimeConsole()); perf.Start(); /* -- Performance Test Start -- */ GtaHotelCacheService service = new GtaHotelCacheService();List<TGtahotel> hotels = service.getAllHotelList();displayHotels(hotels);/* -- Performance Test End -- */ perf.Stop(); perf.PrintTime(); /* -- Performance Test End -- */ in = new Scanner(System.in);System.out.println("Try Again(Y/N): ");key = in.nextLine();}}private static void displayHotels(List<TGtahotel> hotels) { System.out.println("There are " + hotels.size() + " records.");}}