简单实现三种清除cache时的排序策略

CacheManager类
使用一个HashMap来缓存从数据库中查询出的Object,并提供获取,存放,清除的方法
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

class CostComparator implements Comparator {
public int compare(Object o1, Object o2) {
return ((Double) o1).compareTo((Double) o2);
}

public boolean equals(Object o) {
return super.equals(o);
}
}

public class CacheManager {
//三种清除cache时的排序策略
public static int LRU = 0;

public static int LFU = 1;

public static int MIX = 2;

//使用一个HashMap来存储Object
private HashMap cacheHashMap = new HashMap();

private int CACHE_CAPACITY = 100;

private int TRESHOLD = 90;

private int purgeAlgorithm;

private long hitCount = 0;

private long missCount = 0;

public CacheManager(int purgeAlgorithm, int cacheCapacity, int treshold) {
this.purgeAlgorithm = purgeAlgorithm;
CACHE_CAPACITY = cacheCapacity;
TRESHOLD = treshold;
}

public CacheManager(int purgeAlgorithm) {
this.purgeAlgorithm = purgeAlgorithm;
}

/**
*根据字符串identifier从cacheHashMap容器中获取cachedObject对象
*如果cacheHashMap中没有identifier键,或cachedObject已经过时,则返回null,
*同时missCount值加1
*否则获取对应的cachedObject对象,并使hitCount加1
*/
public synchronized Object getCache(String identifier) {
CachedObject cachedObject = (CachedObject) cacheHashMap.get(identifier);
Object obj = null;

if (cachedObject == null) {
missCount++;
} else if (cachedObject.isExpired()) {
cacheHashMap.remove(identifier);
missCount++;
} else {
cachedObject.incNumAccess();
cachedObject.setLastAccessTime(new Date());
hitCount++;
obj = cachedObject.getObject();
}
return obj;
}

public synchronized void invalidate(String identifier) {
cacheHashMap.remove(identifier);
}

public long getHitCount() {
return hitCount;
}

public long getMissCount() {
return missCount;
}

public long getCurrentCacheSize() {
return cacheHashMap.size();
}

public synchronized void putCache(Object object, String id,
int minutesToLive) {
CachedObject cachedObject = new CachedObject(object, id, minutesToLive);
if (cacheHashMap.size() == CACHE_CAPACITY) {
sweep();
}
cacheHashMap.put(id, cachedObject);
}

/**
*cacheHashMap容器的整理
*先将超时的cachedObject清除,
*当cachedObject数量大于TRESHOLD时,将访问频率小(次数小)的cachedObject清除
*/
public synchronized void sweep() {
TreeMap costTreeMap = new TreeMap(new CostComparator());
for (Iterator i = cacheHashMap.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
CachedObject cachedObject = (CachedObject) entry.getValue();
if (cachedObject.isExpired()) {
cacheHashMap.remove(entry.getKey());
} else {
double cost = 0.0;
switch (purgeAlgorithm) {
case 0:
cost = cachedObject.getLFUCost();
break;
case 1:
cost = cachedObject.getLRUCost();
break;
default:
cost = cachedObject.getMixCost();
}
costTreeMap.put(new Double(cost), entry.getKey());
}
}

// delete to treshold
for (int i = cacheHashMap.size(); i > TRESHOLD; i--) {
Object kk = costTreeMap.firstKey();
Object k = costTreeMap.get(kk);
cacheHashMap.remove(k);
costTreeMap.remove(kk);
}
}

public void clearCache() {
hitCount = 0;
missCount = 0;
cacheHashMap.clear();
}

/**
*将字符数组生成形如:"keys1/keys2/keys3"的字符串
*/
public static String createKey(String[] keys) {
StringBuffer newKey = new StringBuffer("");
for (int i = 0; i < keys.length; i++)
newKey.append(keys[i]).append("/");
return newKey.toString();
}
}

//==============================
//DAOCacheManager类
//持有一个静态的CacheManager类对象,提供对其的操作方法
//业务方法都要通过他来使用cacheManager
//---------------------------------------------------------
// Application: Company Applcation
// Author : Cao guangxin
// File : DAOCacheManager.java
//
// Copyright 2006 RelationInfo Software
// Writed at Wed Apr 12 08:58:55 CST 2006
// writed by Eclipse SDK
// Visit http://www.37signals.cn
//---------------------------------------------------------

package net.cn37signals.company.dao;

import java.text.MessageFormat;

import net.cn37signals.company.util.CacheManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DAOCacheManager {
private static Log log = LogFactory.getFactory().getInstance("DAOCacheManager");
//cacheManager是静态的,供多个线程公用
private static CacheManager cacheManager = new CacheManager(CacheManager.MIX);

/**
*从cache中获取对象
*/
public static Object getCache(String identifier) {
if (log.isInfoEnabled()) {
Object[] o = {new Long(cacheManager.getHitCount()), new Long(cacheManager.getMissCount())};
log.info(MessageFormat.format(" [DAOCacheManager] getCache: {0} hits, {1} misses", o));
}
return cacheManager.getCache(identifier);
}

/**
*将对象放入cache中
*/
public static void putCache(Object object, String id, int minutesToLive) {
if (log.isInfoEnabled()) {
log.info(" [DAOCacheManager] putCache");
}
cacheManager.putCache(object, id, minutesToLive);
}

public static void invalidate(String id) {
cacheManager.invalidate(id);
}

}
//=====================
CachedObject类
对要放入cache的对象进行包装
//---------------------------------------------------------
// Application: Company Applcation
// Author : Cao guangxin
// File : CachedObject.java
//
// Copyright 2006 RelationInfo Software
// Writed at Wed Apr 12 08:58:55 CST 2006
// writed by Eclipse SDK
// Visit http://www.37signals.cn
//---------------------------------------------------------

package net.cn37signals.company.util;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class CachedObject {

public Object object = null;
private Date dateofExpiration = null;
private String identifier = null;
private Date lastAccessTime = new Date();
private long numAccess = 1;
private int size;

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

public CachedObject(Object obj, String id, int minutesToLive) {
this.object = obj;
this.identifier = id;

size = objectSize(obj);
lastAccessTime = new Date();
// minutesToLive of 0 means it lives on indefinitely.
if (minutesToLive != 0) {
Calendar cal = Calendar.getInstance();
cal.setTime(lastAccessTime);
cal.add(cal.MINUTE, minutesToLive);
dateofExpiration = cal.getTime();
}
}

public void setLastAccessTime(Date lastAccessTime) {
this.lastAccessTime = lastAccessTime;
}

public boolean isExpired() {
// Remember if the minutes to live is zero then it lives forever!
if (dateofExpiration != null && dateofExpiration.before(new Date())) {
return true;
}
return false;
}

public String getIdentifier() {
return identifier;
}

public Object getObject() {
return object;
}

public Date getDateofExpiration() {
return (this.dateofExpiration);
}

public Date getLastAccessTime() {
return (this.lastAccessTime);
}

public long getNumAccess() {
return (this.numAccess);
}

public long getSize() {
return (this.size);
}

public double getMixCost() {
long milis = new Date().getTime() - lastAccessTime.getTime();
if(milis == 0) {
milis = 1;
}
return (double)numAccess / (double)milis / (double)size;
}

public double getLRUCost() {
long milis = new Date().getTime() - lastAccessTime.getTime();
if(milis == 0) {
milis = 1;
}
return 1.0/(double)milis;
}

public double getLFUCost() {
return (double) numAccess;
}

public void incNumAccess() {
numAccess++;
}

public boolean equals(Object o2) {
try {
String key2 = ((CachedObject) o2).getIdentifier();
return identifier.equals(key2);
} catch (Exception e) {
return false;
}
}

private static int objectSize(Object o) {
try {
int size = ((List) o).size();
return size + 1;
} catch (Exception e) {
return 1;
}
}

}
//==============================
//使用方法
public List list(int offset, int limit) throws SQLException {
String[] objKeys = {"Users", "list", String.valueOf(offset), String.valueOf(limit)};
String objKey = CacheManager.createKey(objKeys);
ArrayList list = (ArrayList) DAOCacheManager.getCache(objKey);
//如果cache的hashmap中有,直接取出,没有则从数据库中查询,并放入hashmap中
if (list != null)
return list;
//--
//从数据库中查询(略)
//--
//将查询结果放入cache
DAOCacheManager.putCache(list, objKey, 1);
return list;
}

你可能感兴趣的:(java,apache,eclipse,.net,cache)