在J2EE应用开发中,经常会碰到需缓存一些不经常变的信息作为应用全局信息,加快应用的处理速度。但不经常变,不代表不会变,一旦变化了,势必就要更新缓存,此时应该如何处理缓存更新问题呢?通行做法如下:
1.一次加载法
描述:在应用启动时做一次加载,在信息变更时,重启应用,重新加载,实现缓存变更。
优点:单线程,安全,处理方便。
缺点:暴力,可用性差,必须重启应用。
2.单线程更新法
描述:首先在应用启动时先加载一次,然后在信息变更时,通知一个另外的单线程来进行
更新操作。最常用的方法在数据库里标志标志,多线程通过更新数据库标志来
通知有变化, 然后但更新线程定时执行更新操作。
优点:将并发问题转化为单线程问题,代码相对安全,效率也高。
缺点:逻辑被分离,实时性难以保证(所以被称为准实时)。
3.并发控制,乐观锁定法
描述:在使用参数时,判断参数当前版本是否是最新版本,不是最新版本做更新操作,
更新时进行并发控制, 同时再判断是否已被其它线程更新过,最大限度地减低
锁控制范围,降低锁竞争,从而提高效率。此种做法一般称为乐观锁定法。
优点:逻辑清晰,实时控制,效率较高
缺点:代码复杂,且更新参数要有版本号的设计
乐观锁定法DEMO:
public class ChannelRouteKBaseFactory{
package com.bill99.seashell.fsp.channelrouter.service.impl;
//单例
private static KnowledgeBaseFactory instance = new ChannelRouteKBaseFactory();
private final static Object lock = new Object();
private long version = 0L;
private Object result = null;
//私有构造函数
private ChannelRouteKBaseFactory(){
};
public static KnowledgeBaseFactory getInstance(){
return instance;
}
public Object getObject(){
//取参数实际版本号(数据库,或远程等地方)
long remoteVersion = …. ;
//记录当前线程取得缓存的版本号
long localThreadVersion= version;
//如果缓存尚未更新过本线程取得当前缓存版本号已经过时 ,
//则进行缓存更新操作,此条件虽在并发控制内,
//就是为了减少并发时的锁竞争,被称为乐观锁定
//(言外之意就是认为此时只有本线程访问)
if(localVersion==0 || localVersion < remoteVersion){
synchronized (lock){
//由于是乐观认为是只有本线程访问,实际进行更新时,再进行一次版本的比较
//比较实际缓存版本与本线程取得版本相同,在证明确实只有本线程访问,
//则进行更新操作,负责返回最新的版本
if(this.version==localVersion){
//更新操作 result=…;
return result;
}else{
return result;
}
}else{
return result;
}
}
}