java中的缓存思想与相应的设计模式

这几天刚做完项目以后,又看起关于设计模式的书籍,在学习的过程中,频繁见到缓存,而在s2sh框架中,

也会经常使用到一级缓存与二级缓存,实现原理与实现的响应机制在此进行相应的总结:

简单的讲,缓存就是将默写资源或者数据会频繁会被使用到的数据或者资源存储在系统外,比如数据库、

硬盘文件等,那么每次操作这些数据的时候都从数据库或者硬盘上去获取,速度会很慢,会造成性能问题。

一个简单的解决方法就是:把这些数据缓存到内存里面,每次操作的时候,先到内存里面找,看有没有这

些数据,如果有,那么就直接使用,如果没有那么就获取它,并设置到缓存中,下一次访问的时候就可以

直接从内存中获取了。从而节省大量的时间,当然,缓存是一种典型的空间换时间的方案。,在Java中最

常见的一种实现缓存的方式就是使用Map。

缓存的实现基本步骤是:

(1)先到缓存里面查找所要查找的想用数据,看看是否存在需要使用的数据
(2)如果没有找到,那么就创建一个满足要求的数据,然后把这个数据设置回到缓存中,以备下次使用
(3)如果找到了相应的数据,或者是创建了相应的数据,那就直接使用这个数据。


public class JavaCache {
/**
* 缓存数据的容器,定义成Map是方便访问,直接根据Key就可以获取Value了 key选用String是为了简单
*/
private Map<String, Object> map = new HashMap<String, Object>();


/**
* 从缓存中获取值

* @param key
*            设置时候的key值
* @return key对应的Value值
*/
public Object getValue(String key) {
// 先从缓存里面取值
Object obj = map.get(key);
// 判断缓存里面是否有值
if (obj == null) {
// 如果没有,那么就去获取相应的数据,比如读取数据库或者文件
// 这里只是演示,所以直接写个假的值
obj = key + ",value";
// 把获取的值设置回到缓存里面
map.put(key, obj);
}
// 如果有值了,就直接返回使用
return obj;
}
}

这里只是缓存的基本实现,还有很多功能都没有考虑,比如缓存的清除,缓存的同步等等。当然,Java的
缓存还有很多实现方式,也是非常复杂的,现在有很多专业的缓存框架,更多缓存的知识,这里就不再去

讨论了。

Hibernate有两个级别的缓存.一个是Session级别的缓存,它是第一级别缓存属于进程范围内的缓存,

由Hibernate自行管理一般情况下无需进行干预.另一个是SessionFactory级别的缓存,它是第二级别的

缓存属于集群范围与进程范围的缓存.它可以自己进行配置与更改,而且可以动态加载与卸载,曾经有

记者问Hibernate之父Gavin King,说在hibernate中什么是让他最骄傲的开发,Gavin King就说最重要的

就是其中用到的缓存技术,可想而知,缓存技术的重要性。

在java的单例设计模式中,也涉及到缓存的使用;

注:单例设计模式的本质:控制实例的数目.

/**
 *扩展单例模式,控制实例数目为3个 
 */
public class OneExtend {
/**
* 定义一个缺省的key值的前缀
*/
private final static String DEFAULT_PREKEY = "Cache";
/**
*
缓存实例的容器
*/
private static Map<String,OneExtend> map = new HashMap<String,OneExtend>();
/**
* 用来记录当前正在使用第几个实例,到了控制的最大数目,就返回从1开始
*/
private static int num = 1;
/**
* 定义控制实例的最大数目
*/
private final static int NUM_MAX = 3; 
private OneExtend(){}
public static OneExtend getInstance(){
String key = DEFAULT_PREKEY+num;
OneExtend oneExtend = map.get(key);
if(oneExtend==null){
oneExtend = new OneExtend();
map.put(key, oneExtend);
}
//把当前实例的序号加1
num++;
if(num > NUM_MAX){
//如果实例的序号已经达到最大数目了,那就重复从1开始获取
num = 1;
}
return oneExtend;
}

public static void main(String[] args) {
OneExtend t1 = getInstance();
OneExtend t2 = getInstance();
OneExtend t3 = getInstance();
OneExtend t4 = getInstance();
OneExtend t5 = getInstance();
OneExtend t6 = getInstance();

System.out.println("t1=="+t1);
System.out.println("t2=="+t2);
System.out.println("t3=="+t3);
System.out.println("t4=="+t4);
System.out.println("t5=="+t5);
System.out.println("t6=="+t6);
}
}


缓存技术虽好,但缓存技术在Web应用中依然存在相应的问题,那就是缓存数据存放时间问题,在Web应用中,

比如说登录人员的相关权限的问题,大多数是放在session中进行缓存的,但session超时时,就会被清除掉;当然了,

如果不是在Web应用中,就得自己来控制了,另外就算是在Web应用中,也不一定非要缓存到session超时才清楚,

总之,控制缓存数据应该被缓存多长时间,是实现高效缓存的一个问题点。

另一个问题,缓存数据和真实数据的同步问题,缓存中的数据在运行期间会发生变化,那么缓存中的数据就应该和

数据库中的数据同步,以保持一致,否则就会出错,如何合理的同步数据,也是实现高效缓存的另一个问题点。

最后,就是缓存的多线程并发的控制,对于缓存的数据,有些操作是从缓存中取数据,有些操作时想缓存中添加数

据,有些操作是在清除过期的缓存数据等等,而在一个多线程的环境下,如何合理的进行对缓存进行并发控制,也是

实现缓存的一个问题点。

这里就牵涉到一个设计模式使用的问题,那就是:享元设计模式,此设计模式的重点就在于分离变与不变,把一个

对象的状态分成内部状态和外部状态,内部状态是不变的,而外部状态是可变的,然后通过共享不变的部分,达到减

少对象数量并节约内存的目的,还有一点就是,在享元需要的时候,可以从外部传入外部状态给共享的对象,共享对

象会在功能处理的时候,使用自己内部的状态和这些外部的状态。

还有,在享元模式中,为了创建和管理共享的享元部分,可以引入享元工厂,享元工厂中包含享元对象的实例池,享

元对象就是缓存在这个实例池中的。



曾经请教过,有人说在实际的工业级的实例池的实现中有两个基本的难点:一个是动态控制实例的数量,另一个就是

动态分配实例来提供给外部使用,但这些实现需要相应算法来做保证。后续……

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

feihong247

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值