关于OSCache的使用
关键字: 缓存的使用听说OSCache的性能不行,我没测试过,但看到在应用过程中使用却非常广泛,因此对OSCache的使用看了一些资料,现对片断摘录如下:
OSCache.java
import java.util.Properties;
import com.opensymphony.oscache.base.EntryRefreshPolicy;
import com.opensymphony.oscache.base.NeedsRefreshException;
import com.opensymphony.oscache.base.persistence.CachePersistenceException;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;
import com.opensymphony.oscache.web.filter.ExpiresRefreshPolicy;
import com.util.*;
public class OSCache implements Cache {
private GeneralCacheAdministrator cache;
private static OSCache instance;
public OSCache() {
this.cache = new GeneralCacheAdministrator();
}
public OSCache(Properties prop) {
this.cache = new GeneralCacheAdministrator(prop);
}
public synchronized static OSCache getInstance() {
if (instance == null) {
instance = new OSCache();
}
return instance;
}
public void setCacheCapacity(int cacheCapacity) {
this.cache.setCacheCapacity(cacheCapacity);
}
public Object get(Object key) throws CachePersistenceException {
try {
return this.cache.getFromCache(String.valueOf(key));
} catch (NeedsRefreshException e) {
cache.cancelUpdate(String.valueOf(key));
return null;
}
}
public Object get(Object key, int time) throws CachePersistenceException {
try {
return this.cache.getFromCache(String.valueOf(key), time);
} catch (NeedsRefreshException e) {
cache.cancelUpdate(String.valueOf(key));
return null;
}
}
public Object getkey(int time) throws CachePersistenceException {
String key = StrUtils.randomAlphanumeric(10);
try {
while (this.cache.getFromCache(key) != null) {
key = StrUtils.randomAlphanumeric(10);
}
return key;
} catch (NeedsRefreshException e) {
return key;
}
}
public void input(Object key, Object value)
throws CachePersistenceException {
this.cache.putInCache(String.valueOf(key), value);
}
public void input(Object key, Object value, int n)
throws CachePersistenceException {
EntryRefreshPolicy Policy = new ExpiresRefreshPolicy(n);
this.cache.putInCache(String.valueOf(key), value, Policy);
}
public void remove(Object key) throws CachePersistenceException {
this.cache.flushEntry(String.valueOf(key));
}
public void clear() throws CachePersistenceException {
this.cache.flushAll();
}
public void destroy() throws CachePersistenceException {
this.cache.destroy();
}
}
//Cache.java接口
import com.opensymphony.oscache.base.persistence.CachePersistenceException;
public interface Cache {
Object get(Object key) throws CachePersistenceException;
Object get(Object key, int time) throws CachePersistenceException;
void input(Object key, Object value) throws CachePersistenceException;
void input(Object key, Object value, int i)
throws CachePersistenceException;
void remove(Object key) throws CachePersistenceException;
void clear() throws CachePersistenceException;
void destroy() throws CachePersistenceException;
Object getkey(int time) throws CachePersistenceException;
}
//CacheManager .java
import java.util.*;
public class CacheManager {
private static Map cacheMap = new HashMap();
// private static Config config = ConfigManager.getConfig();
private CacheManager() {
}
public static Cache getCache(Class clazz) {
return getCache(clazz.getName());
}
public static Cache getCache() {
return getCache();
}
public static Cache getCache(String cacheId) {
Cache cache = null;
cache = (Cache) cacheMap.get(cacheId);
if (cache == null) {
// cache = new OSCache(config.getProperties());
cacheMap.put(cacheId, cache);
}
return cache;
}
}
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=778146
评论
正在学习缓存!
看到一个缓存的例子, 控制类:UtilCache,里面有四个重要的属性,一是保存本身的hashMap,这是为了对把不同类型的缓存统一放到这个hashMap中,当然这个可以设置成控制类的静态属性。
二是保存数据的HashMap,还有一个LinkList类来控制data的生命周期,这个例子跟上述原理相似,不重述,不过保存data的类中用到了JAVA的软引用,这个概念平常接触比较少,因此在这里描述一下。
保存数据的类:
public static class CacheLine {
public Object valueRef = null;
public long loadTime = 0;
public boolean useSoftReference = false;
public CacheLine(Object value, boolean useSoftReference) {
if (useSoftReference) {
this.valueRef = new java.lang.ref.SoftReference(value);
} else {
this.valueRef = value;
}
this.useSoftReference = useSoftReference;
}
public CacheLine(Object value, boolean useSoftReference, long loadTime) {
this(value, useSoftReference);
this.loadTime = loadTime;
}
public Object getValue() {
if (valueRef == null)
return null;
if (useSoftReference) {
return ((java.lang.ref.SoftReference) valueRef).get();
} else {
return valueRef;
}
}
public void setUseSoftReference(boolean useSoftReference) {
if (this.useSoftReference != useSoftReference) {
synchronized (this) {
this.useSoftReference = useSoftReference;
if (useSoftReference) {
this.valueRef = new java.lang.ref.SoftReference(this.valueRef);
} else {
this.valueRef = ((java.lang.ref.SoftReference) this.valueRef).get();
}
}
}
}
}
这里用到了java.lang.ref.SoftReference
不知道几类引用的区别,现在下面描述一下:
在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,否则就把它扔到垃圾箱,由清洁工人收走。一般说来,如果物品已经被扔到垃圾箱,想再把它捡回来使用就不可能了。
但有时候情况并不这么简单,你可能会遇到类似鸡肋一样的物品,食之无味,弃之可惜。这种物品现在已经无用了,保留它会占空间,但是立刻扔掉它也不划算,因为也许将来还会派上用场。对于这样的可有可无的物品,一种折衷的处理办法是:如果家里空间足够,就先把它保留在家里,如果家里空间不够,即使把家里所有的垃圾清除,也无法容纳那些必不可少的生活用品,那么再扔掉这些可有可无的物品。
从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
1.强引用(StrongReference)
本章前文介绍的引用实际上都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
2.软引用(SoftReference)
如果一个对象只具有软引用,那就类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
3.弱引用(WeakReference)
如果一个对象只具有弱引用,那就类似于可有可无的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
4.虚引用(PhantomReference)
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
public class Cache implements Cacheable {
/**
* 因为System.currentTimeMillis()执行非常耗费性能,因此如果get操作都执行
* 这条语句将会形成性能瓶颈, 通过一个全局时间戳来实现每秒更新
* 当然,这意味着在缓存过期时间计算上有一到几秒的误差
*/
protected static long currentTime = CacheTimer.currentTime;
//CacheObject对象
protected HashMap cachedObjectsHash;
//accessed LinkedList 最经常访问的排列在最前面
protected LinkedList lastAccessedList;
//以缓存加入顺序排列,最后加入排在最前面;越早加入的排在最后面
protected LinkedList ageList;
//缓存最大限制 默认是128k 可根据内存设定,越大性能越高
protected int maxSize = 128 * 1024;
//当前缓存的大小
protected int size = 0;
//最大生命周期时间,默认是没有
protected long maxLifetime = -1;
//缓存的击中率,用于评测缓存效率
protected long cacheHits, cacheMisses = 0L;
public Cache() {
// 构造HashMap. 默认capacity 是11
// 如果实际大小超过11,HashMap将自动扩充,但是每次扩充都
// 是性能开销,因此期初要设置大一点
cachedObjectsHash = new HashMap(103);
lastAccessedList = new LinkedList();
ageList = new LinkedList();
}
public Cache(int maxSize) {
this();
this.maxSize = maxSize;
}
public Cache(long maxLifetime) {
this();
this.maxLifetime = maxLifetime;
}
public Cache(int maxSize, long maxLifetime) {
this();
this.maxSize = maxSize;
this.maxLifetime = maxLifetime;
}
public int getSize() { return size; }
public int getMaxSize() { return maxSize; }
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
// 有可能缓存大小超过最大值,需要激活删除清理动作
cullCache();
}
public synchronized int getNumElements() {
return cachedObjectsHash.size();
}
/**
* 增加一个Cacheable对象
* 因为HashMap不是线程安全的,所以操作方法要使用同步
* 如果使用Hashtable就不必同步
*/
public synchronized void add(Object key, Cacheable object) {
// 删除已经存在的key
remove(key);
int objectSize = object.getSize();
// 如果被缓存对象的大小超过最大值,就放弃
if (objectSize > maxSize * .90) { return; }
size += objectSize;
//创建一个CacheObject对象
CacheObject cacheObject = new CacheObject(object, objectSize);
cachedObjectsHash.put(key, cacheObject); //保存这个CacheObject
// 加入accessed LinkedList,Jive自己的LinkedList在加入时可以返回值
LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key);
// 保存引用
cacheObject.lastAccessedListNode = lastAccessedNode;
// 加入到age LinkedList
LinkedListNode ageNode = ageList.addFirst(key);
// 这里直接调用System.currentTimeMillis();用法值得讨论
ageNode.timestamp = System.currentTimeMillis();
// 保存引用
cacheObject.ageListNode = ageNode;
// 做一些清理工作
cullCache();
}
/**
* 从缓存中获得一个被缓存的对象,这个方法在下面两种情况返回空
* <li>该对象引用从来没有被加入缓存中
* <li>对象引用因为过期被清除</ul>
*/
public synchronized Cacheable get(Object key) {
// 清除过期缓存
deleteExpiredEntries();
//以Key从缓存中获取一个对象引用
CacheObject cacheObject = (CacheObject)cachedObjectsHash.get(key);
if (cacheObject == null) {
// 不存在,增加未命中率
cacheMisses++;
return null;
}
// 存在,增加命中率
cacheHits++;
// 从accessed LinkedList中将对象从当前位置删除
// 重新插入在第一个
cacheObject.lastAccessedListNode.remove();
lastAccessedList.addFirst(cacheObject.lastAccessedListNode);
return cacheObject.object;
}
…
}
Jive的Cache总体来说实现得不是非常精简和有效。它是针对每个具体数据对象逐个实现缓冲,这种“穷尽”的办法不是实践所推荐的用法。通过使用动态代理模式,可以根据具体方法的不同来实现缓存是值得推荐的做法。Jive的缓存实现得比较简单,可以用来学习和研究缓存机制。
Jive中的Cache实现了缓存机制的大部分行为,它是将对象用惟一的关键字Key作标识保存在HashMap或Hashtable中。当然,必须知道这些对象的大小,这个前提条件的设定可以保证缓存增长时不会超过规定的最大值。
如果缓存增长得太大,一些不经常被访问的对象将首先从缓存中删除。如果设置了对象的最大生命周期时间,即使这个对象被反复频繁访问,也将从缓存中删除。这个特性可以适用于一些周期性需要刷新的数据,如来自数据库的数据。
在Cach中除了getObject()方法的性能依据缓存大小,其他方法的性能都是比较快的。一个HashMap用来实现快速寻找,两个LinkedList中一个以一定的访问顺序来保存对象,叫accessed LinkedList;另外一个以它们加入缓存的顺序保存这些对象,这种保存对象只是保存对象的引用,叫 age LinkedList。注意,这里的LinkedList不是JDK中的LinkedList,而是Jive自己定义的LinkedList。
当对象被加入缓存时,首先被CacheObject封装。封装有以下信息:对象大小(以字节计算),一个指向accessed LinkedList的引用,一个指向age LinkedList的引用。
当从缓存中获取一个对象如ObjectA时,首先,HashMap寻找到指向封装ObjectA等信息的CacheObject对象。然后,这个对象将被移动到accessed LinkedList的前面,还有其他一些动作如缓存清理、删除、过期失效等都是在这个动作中一起触发实现的。
缓存中对象是原对象的映射,如何确保缓存中对象和原对象的一致性?即当原对象发生变化时,缓存中的对象也必须立即更新。这是缓存机制需要解决的另外一个基本技术问题。
Jive中是在原对象发生变化时,立即进行清除缓存中对象,如ForumMessage对象的创建。在DbForumThread的AddMessage方法中有下列语句:
factory.cacheManager.threadCache.remove(this.id);
factory.cacheManager.forumCache.remove(this.forumID);
即当有新的帖子加入时,将ForumThreadCache和ForumCache相关缓冲全部清除。这样,当有相关对象读取时,将直接从数据库中读取,这是一种非常简单的缓存更新方式。
在复杂的系统,例如有一台以上的服务器运行着Jive系统。如果一个用户登陆一台服务器后,通过这台服务器增加新帖。那么按照上述原理,只能更新本服务器JVM中的缓存数据,而其他服务器则无从得知这种改变,这就需要一种分布式的缓存机制。
发表评论
- 浏览: 108022 次
- 性别:


- 详细资料
搜索本博客
我的相册
共 45 张
链接
最新评论
-
续 一位朋友辞职引起的思 ...
好文谢谢,指路人啊
-- by mackmack -
续 一位朋友辞职引起的思 ...
文章总结的真是好。准备创业的哥们建议doul都来看看,看自己是不是真的准备好了迎 ...
-- by hellofuck -
致陈年叔
这么一个有才的人,怎么会有这种心结呢?
-- by Ethip -
续 一位朋友辞职引起的思 ...
作者看来是对现在的IT行业有很长时间的研究吧,不过,现实就是这样。很残酷! 人在 ...
-- by dtctve67 -
Tomcat启动时报filterStar ...
tomat/server/lib目录下的commons-digester.jar ...
-- by wangyazhen






评论排行榜