使用Hashtable和线程技术制作自己简单的内存缓存

[b]1. 首先,我们要做一个缓存数据类[/b]
这个数据类要有一个数据成员,存放你的缓存数据,可以是一个类,也可以是一个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;
}
}


[b]2.在有了缓存数据类以后,我们将建立一个缓存操作类[/b]


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();
}

...

}


我们看到这个缓存操作类是采用singleton模式的,因为我们的缓存可能要被多次调用,而
它只占用我们内存中的同一块空间,因为必须要采用singleton模式

增加缓存数据

/**
* 添加数据缓存 与方法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.");
}
}


输出结果:
There are 52973 records.
******************************* Performance Log *******************************
Module: Gta Hotel From Cache, Time Consumed: 0h:0m:6s:836ms
*******************************************************************************
Try Again(Y/N):
y
There are 52973 records.
******************************* Performance Log *******************************
Module: Gta Hotel From Cache, Time Consumed: 0h:0m:0s:0ms
*******************************************************************************
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值