java缓存技术(转)

最近在做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

时间: 2024-10-30 03:30:43

java缓存技术(转)的相关文章

JAVA缓存技术之EhCache(转)

最近再ITEYE上看到关于讨论JAVA缓存技术的帖子比较多,自己不懂,所以上网大概搜了下,找到一篇,暂作保存,后面如果有用到可以参考.此为转贴,帖子来处:http://cogipard.info/articles/cache-static-files-with-jnotify-and-ehcache 介绍 JNotify:http://jnotify.sourceforge.net/,通过JNI技术,让Java代码可以实时的监控制定文件夹内文件的变动信息,支持Linux/Windows/MacO

PHP缓存技术

1普遍缓存技术 数据缓存:这里所说的数据缓存是指数据库查询缓存,每次访问页面的时候,都会先检测相应的缓存数据是否存在,如果不存在,就连接数据库,得到数据,并把查询结果序列化后保存到文件中,以后同样的查询结果就直接从缓存表或文件中获得. 用的最广的例子看Discuz的搜索功能,把结果ID缓存到一个表中,下次搜索相同关键字时先搜索缓存表. 举个常用的方法,多表关联的时候,把附表中的内容生成数组保存到主表的一个字段中,需要的时候数组分解一下,这样的好处是只读一个表,坏处就是两个数据同步会多不少步骤,数

请教:java 缓存技术书籍 或 研究方法

问题描述 我想研究下java的缓存技术,但是不知道如何下手,请高手指导一下,有没有相关的书籍或方法 解决方案 如果是有点开发经验的程序员,建议直接看reference分布式的memcachehttp://memcached.org/普通的cacheoscache enhance ehcache.org/

Hibernate框架中的缓存技术详解_java

本文实例讲述了Hibernate框架中的缓存技术.分享给大家供大家参考,具体如下: Hibernate框架的缓存分为Session的缓存.SessionFactory的缓存,也称为一级缓存和二级缓存. 一级缓存: 一级缓存是Session级的缓存,其生命周期很短,与Session相互对应,由Hibernate进行管理,属于事务范围的缓存.当程序调用 Session的load()方法.get()方法.save()方法.saveOrUpdate()方法.update()方法或查询接口方法时,Hibe

【框架】[Hibernate]多表操作与缓存技术

转载请注明出处:http://blog.csdn.net/qq_26525215 本文源自[大学之旅_谙忆的博客] 多表操作 关系型数据库具有三种常用关系:一对一关系.一对多关系和多对多关系. 建立了一对多关系的表之间,一方中的表叫"主表",多方中的表叫"子表":两表中相关联的字段,在主表中叫"主键",在子表中称"外键". 一对多关系操作 我们以院系表与学生表为例. 在Hibernate映射中,在院系表中添加一个集合属性,集合

如何在Windows Azure中使用Java相关技术

我们刚刚发布了一个新教程和示例代码,以阐述如何在Windows Azure中使用 Java 相关技术.在该指南中,我们提供了分步教程,说明如何将 Java Spring Framework 应用程序(PetClinic 示例应用程序)迁移到 Windows Azure 云.此文档附带的代码同样也发布在 GitHub 中.我们鼓励 Java 开发人员下载并探索此新示例和教程. Windows Azure 是一个开放的云平台,它支持各种编程语言和框架,包括 Microsoft .NET.Java.N

如何做好java的技术演讲

问题描述 如何做好java的技术演讲 java的类和属性.方法.构造方法如何演讲才更具有技术性 俄罗斯方块技术实现的演讲

缓存技术方案改造思考

这是我对一个正在进行的重构项目,缓存技术方案改造点之一的一个想法: rc现有的实时缓存(其实也是准实时,失效时间的存在)设计: 存在的问题:现有的实时缓存方案(也并非真正意义上的实时,缓存失效时间的存在),与上游核心系统耦合度较高,核心系统强依赖下游欠核心系统,而且目前的查询服务性能也存在问题,比如区域销售豆腐块接口返回的数据量大,并且从tair->rc,rc->delivery需要经过两次网络传输,这之间网络传输及序列化.反序列化消耗大,而且出现问题时,由于排查链路和时间周期都长: 升级方案

使用asp缓存技术,提高asp承载能力

其实当你的web站点采用asp技术建立的初期,可能会感觉到的是asp动态网页技术带来的便利性,以及随意修改性.自如的http控制.但随着访问量的增加,你一定会发现自己的站点访问速度会越来越慢,IIS重新启动得越来越频繁. 一.什么是ASP缓存/为什么要缓存 其实当你的web站点采用asp技术建立的初期,可能会感觉到的是asp动态网页技术带来的便利性,以及随意修改性.自如的http控制.但随着访问量的增加,你一定会发现自己的站点访问速度会越来越慢,IIS重新启动得越来越频繁.那么,你一定想怎么优化