您的位置:首页 > 编程语言 > Java开发

java缓存技术

2015-10-14 22:36 375 查看
最近在做java缓存,了解了一下.
以下仅是对map对方式讨论。没有对点阵图阵讨论。
作缓存要做以下2点: 
1:清理及更新缓存时机的处理:
   . 虚拟机内存不足,清理缓存
   .. 缓存时间超时,或访问次数超出, 启动线程更新
2:类和方法的反射 (线程嵌套调用)
   reflect.invoke的使用。

代码如下:

package atest.hiyaCache;

/**

 *

 * @author hiyachen

 * @version $Revision$

 */

public class AddrDetail {

    public String latelyKeyword(String province, String city, String county){

        System.out.println("AddrDetail.latelyKeyword=" + province + city + county);

        return province + city + county;

    }

    public String buildCache(String latelyKeyword){

        System.out.println("AddrDetail.buildCache=" + latelyKeyword);

        return latelyKeyword;

    }

}

package atest.hiyaCache;

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;

    }

}

package atest.hiyaCache;

import java.lang.reflect.Method;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Hashtable;

import org.apache.commons.logging.Log;   //commons-loggings-1.1.1.jar

import org.apache.commons.logging.LogFactory;

public class CacheOperation {

    private static final Log log = LogFactory.getLog(CacheOperation.class);

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

    }

    /**

     * 取得缓存中的数据

     * 与方法addCacheData(String key, Object data)配合使用

     * @param key

     * @param intervalTime 缓存的时间周期,小于等于0时不限制

     * @param maxVisitCount 访问累积次数,小于等于0时不限制

     * @return

     */

    public Object getCacheData(String key, long intervalTime, int maxVisitCount) {

        CacheData cacheData = (CacheData)cacheMap.get(key);

        if (cacheData == null) {

            return null;

        }

        if (intervalTime > 0 && (System.currentTimeMillis() - cacheData.getTime()) > intervalTime) {

            removeCacheData(key);

            return null;

        }

        if (maxVisitCount > 0 && (maxVisitCount - cacheData.getCount()) <= 0) {

            removeCacheData(key);

            return null;

        } else {

            cacheData.addCount();

        }

        return cacheData.getData();

    }

    /**

     * 当缓存中数据失效时,用不给定的方法线程更新数据

     * @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 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);

            Object o1 = oc.newInstance();  // add by chf

            returnValue = m.invoke(o1, 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;

    }

    /**

     * 找不到完全匹配的方法时,对参数进行向父类匹配

     * 因为方法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

     */

    private void daemonInvoke(Object o, String methodName,Object[] parameters, String key) {

        if (!threadKeys.contains(key)) {

            InvokeThread t = new InvokeThread(o, methodName, parameters, key);

            t.start();

        }

    }

    /**

     * 些类存放方法的主调对像,名称及参数数组

     * @author hiya

     *

     */

    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 hiya

     *

     */

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

        }

    }

    /**

     * 移除缓存中的数据

     * @param key

     */

    public void removeCacheData(String key) {

        cacheMap.remove(key);

    }

    /**

     * 移除所有缓存中的数据

     *

     */

    public void removeAllCacheData() {

        cacheMap.clear();

    }

    public String toString() {

        StringBuffer sb = new StringBuffer("************************ ");

        sb.append("正在更新的缓存数据: ");

        for (int i = 0; i < threadKeys.size(); i++) {

            sb.append(threadKeys.get(i)).append(" ");

        }

        sb.append("当前缓存大小:").append(cacheMap.size()).append(" ");

        sb.append("************************");

        return sb.toString();

    }

}

 实际使用:

package atest.hiyaCache;

//import javax.swing.text.Document;

import atest.hiyaCache.CacheOperation.MethodInfo;

public class CacheExec {

    /**

     * [メソッドの説明を書きましょう]

     * @param args

     */

    public static void main(String[] args) {

        // TODO 自動生成されたメソッド?スタブ

//        String province = request.getParameter("province");

//        String city= request.getParameter("city");

//        String county= request.getParameter("county");

//        Document doc = XMLBuilder.buildLatelyKeyword(kwm.latelyKeyword(province, city, county));

//        out.write(doc);

        String province = "Jiangsu ";

        String city= "Nanjing ";

        String county= "Jiangning";

        CacheOperation co = CacheOperation.getInstance();

//        MethodInfo mi = co.new MethodInfo(kwm, "latelyKeyword", new Object[]{province, city, county});

//        Document doc = (Document )co.getCacheData(XMLBuilder.class,"buildLatelyKeyword",new Object[]{mi}, 120000, 0);

//        out.write(doc);

       while (true){

            // chf@tsinghua.org.cn 

            MethodInfo mi = co.new MethodInfo(AddrDetail.class, "latelyKeyword", new Object[]{province, city, county});

            // 120000 毫秒(2分钟)更新缓存

            String aa = (String)co.getCacheData(AddrDetail.class,"buildCache",new Object[]{mi}, 120000, 5);

            System.out.println("CacheExec:main=" + aa);

        }    }

}

当缓存次数超过5时,重新执行。看一下执行结果。

AddrDetail.latelyKeyword=Jiangsu Nanjing Jiangning

AddrDetail.buildCache=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

AddrDetail.latelyKeyword=Jiangsu Nanjing Jiangning

AddrDetail.buildCache=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

CacheExec:main=Jiangsu Nanjing Jiangning

AddrDetail.latelyKeyword=Jiangsu Nanjing Jiangning

AddrDetail.buildCache=Jiangsu Nanjing Jiangning

转自http://blog.chinaunix.net/uid-7374279-id-4015786.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: