`
chenwar
  • 浏览: 15202 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最近访客 更多访客>>
社区版块
存档分类
最新评论

学习一种缓存方法(转)

    博客分类:
  • db
阅读更多
CacheManager类
使用一个HashMap来缓存从数据库中查询出的Object,并提供获取,存放,清除的方法
//---------------------------------------------------------
// Application: Company Applcation
// Author     : Cao guangxin
// File       : CacheManager.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.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;
  }
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics