最近項目要引入緩存機制,但是不想引入分布式的緩存框架,所以自己就寫了一個輕量級的緩存實現,有兩個版本,一個是通過timer實現其超時過期處理,另外一個是通過list輪詢。
首先要了解下java1.6中的ConcurrentMap ,他是一個線程安全的Map實現,特別說明的是在沒有特別需求的情況下可以用ConcurrentHashMap。我是想學習一下讀寫鎖的應用,就自己實現了一個SimpleConcurrentHashMap.
- package com.cttc.cache.entity;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashSet;
- import java.util.Map;
- import java.util.Set;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReadWriteLock;
- import java.util.concurrent.locks.ReentrantReadWriteLock;
- public class SimpleConcurrentMap<K, V> implements Map<K, V> {
- final ReadWriteLock lock = new ReentrantReadWriteLock();
- final Lock r = lock.readLock();
- final Lock w = lock.writeLock();
- final Map<K, V> map;
- public SimpleConcurrentMap(Map<K, V> map) {
- this.map = map;
- if (map == null) throw new NullPointerException();
- }
- public void clear() {
- w.lock();
- try {
- map.clear();
- } finally {
- w.unlock();
- }
- }
- public boolean containsKey(Object key) {
- r.lock();
- try {
- return map.containsKey(key);
- } finally {
- r.unlock();
- }
- }
- public boolean containsValue(Object value) {
- r.lock();
- try {
- return map.containsValue(value);
- } finally {
- r.unlock();
- }
- }
- public Set<java.util.Map.Entry<K, V>> entrySet() {
- throw new UnsupportedOperationException();
- }
- public V get(Object key) {
- r.lock();
- try {
- return map.get(key);
- } finally {
- r.unlock();
- }
- }
- public boolean isEmpty() {
- r.lock();
- try {
- return map.isEmpty();
- } finally {
- r.unlock();
- }
- }
- public Set<K> keySet() {
- r.lock();
- try {
- return new HashSet<K>(map.keySet());
- } finally {
- r.unlock();
- }
- }
- public V put(K key, V value) {
- w.lock();
- try {
- return map.put(key, value);
- } finally {
- w.unlock();
- }
- }
- public void putAll(Map<? extends K, ? extends V> m) {
- w.lock();
- try {
- map.putAll(m);
- } finally {
- w.unlock();
- }
- }
- public V remove(Object key) {
- w.lock();
- try {
- return map.remove(key);
- } finally {
- w.unlock();
- }
- }
- public int size() {
- r.lock();
- try {
- return map.size();
- } finally {
- r.unlock();
- }
- }
- public Collection<V> values() {
- r.lock();
- try {
- return new ArrayList<V>(map.values());
- } finally {
- r.unlock();
- }
- }
- }
緩存對象CacheEntity.Java為:
- package com.cttc.cache.entity;
- import java.io.Serializable;
- public class CacheEntity implements Serializable{
- private static final long serialVersionUID = -3971709196436977492L;
- private final int DEFUALT_VALIDITY_TIME = 20;//默認過期時間 20秒
- private String cacheKey;
- private Object cacheContext;
- private int validityTime;//有效期時長,單位:秒
- private long timeoutStamp;//過期時間戳
- private CacheEntity(){
- this.timeoutStamp = System.currentTimeMillis() + DEFUALT_VALIDITY_TIME * 1000;
- this.validityTime = DEFUALT_VALIDITY_TIME;
- }
- public CacheEntity(String cacheKey, Object cacheContext){
- this();
- this.cacheKey = cacheKey;
- this.cacheContext = cacheContext;
- }
- public CacheEntity(String cacheKey, Object cacheContext, long timeoutStamp){
- this(cacheKey, cacheContext);
- this.timeoutStamp = timeoutStamp;
- }
- public CacheEntity(String cacheKey, Object cacheContext, int validityTime){
- this(cacheKey, cacheContext);
- this.validityTime = validityTime;
- this.timeoutStamp = System.currentTimeMillis() + validityTime * 1000;
- }
- public String getCacheKey() {
- return cacheKey;
- }
- public void setCacheKey(String cacheKey) {
- this.cacheKey = cacheKey;
- }
- public Object getCacheContext() {
- return cacheContext;
- }
- public void setCacheContext(Object cacheContext) {
- this.cacheContext = cacheContext;
- }
- public long getTimeoutStamp() {
- return timeoutStamp;
- }
- public void setTimeoutStamp(long timeoutStamp) {
- this.timeoutStamp = timeoutStamp;
- }
- public int getValidityTime() {
- return validityTime;
- }
- public void setValidityTime(int validityTime) {
- this.validityTime = validityTime;
- }
- }
List緩存處理對象:
- package com.cttc.cache.handler;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import com.cttc.cache.entity.CacheEntity;
- import com.cttc.cache.entity.SimpleConcurrentMap;
- /**
- * @projName:WZServer
- * @className:CacheHandler
- * @description:緩存操作類,對緩存進行管理,采用處理隊列,定時循環清理的方式
- * @creater:Administrator
- * @creatTime:2013年7月22日 上午9:18:54
- * @alter:Administrator
- * @alterTime:2013年7月22日 上午9:18:54
- * @remark:
- * @version
- */
- public class CacheListHandler {
- private static final long SECOND_TIME = 1000;
- private static final SimpleConcurrentMap<String, CacheEntity> map;
- private static final List<CacheEntity> tempList;
- static{
- tempList = new ArrayList<CacheEntity>();
- map = new SimpleConcurrentMap<String, CacheEntity>(new HashMap<String, CacheEntity>(1<<18));
- new Thread(new TimeoutTimerThread()).start();
- }
- /**
- * 增加緩存對象
- * @param key
- * @param ce
- */
- public static void addCache(String key, CacheEntity ce){
- addCache(key, ce, ce.getValidityTime());
- }
- /**
- * 增加緩存對象
- * @param key
- * @param ce
- * @param validityTime 有效時間
- */
- public static synchronized void addCache(String key, CacheEntity ce, int validityTime){
- ce.setTimeoutStamp(System.currentTimeMillis() + validityTime * SECOND_TIME);
- map.put(key, ce);
- //添加到過期處理隊列
- tempList.add(ce);
- }
- /**
- * 獲取緩存對象
- * @param key
- * @return
- */
- public static synchronized CacheEntity getCache(String key){
- return map.get(key);
- }
- /**
- * 檢查是否含有制定key的緩沖
- * @param key
- * @return
- */
- public static synchronized boolean isConcurrent(String key){
- return map.containsKey(key);
- }
- /**
- * 刪除緩存
- * @param key
- */
- public static synchronized void removeCache(String key){
- map.remove(key);
- }
- /**
- * 獲取緩存大小
- * @param key
- */
- public static int getCacheSize(){
- return map.size();
- }
- /**
- * 清除全部緩存
- */
- public static synchronized void clearCache(){
- tempList.clear();
- map.clear();
- System.out.println("clear cache");
- }
- static class TimeoutTimerThread implements Runnable {
- public void run(){
- while(true){
- try {
- checkTime();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 過期緩存的具體處理方法
- * @throws Exception
- */
- private void checkTime() throws Exception{
- //"開始處理過期 ";
- CacheEntity tce = null;
- long timoutTime = 1000L;
- //" 過期隊列大小 : "+tempList.size());
- if(1 > tempList.size()){
- System.out.println("過期隊列空,開始輪詢");
- timoutTime = 1000L;
- Thread.sleep(timoutTime);
- return;
- }
- tce = tempList.get(0);
- timoutTime = tce.getTimeoutStamp() - System.currentTimeMillis();
- //" 過期時間 : "+timoutTime);
- if(0 < timoutTime){
- //設定過期時間
- Thread.sleep(timoutTime);
- return;
- }
- System.out.print(" 清除過期緩存 : "+tce.getCacheKey());
- //清除過期緩存和刪除對應的緩存隊列
- tempList.remove(tce);
- removeCache(tce.getCacheKey());
- }
- }
- }
Timer方式
- package com.cttc.cache.handler;
- import java.util.HashMap;
- import java.util.Timer;
- import java.util.TimerTask;
- import com.cttc.cache.entity.CacheEntity;
- import com.cttc.cache.entity.SimpleConcurrentMap;
- /**
- * @projName:WZServer
- * @className:CacheHandler
- * @description:緩存操作類,對緩存進行管理,清除方式采用Timer定時的方式
- * @creater:Administrator
- * @creatTime:2013年7月22日 上午9:18:54
- * @alter:Administrator
- * @alterTime:2013年7月22日 上午9:18:54
- * @remark:
- * @version
- */
- public class CacheTimerHandler {
- private static final long SECOND_TIME = 1000;//默認過期時間 20秒
- private static final int DEFUALT_VALIDITY_TIME = 20;//默認過期時間 20秒
- private static final Timer timer ;
- private static final SimpleConcurrentMap<String, CacheEntity> map;
- static{
- timer = new Timer();
- map = new SimpleConcurrentMap<String, CacheEntity>(new HashMap<String, CacheEntity>(1<<18));
- }
- /**
- * 增加緩存對象
- * @param key
- * @param ce
- */
- public static void addCache(String key, CacheEntity ce){
- addCache(key, ce, DEFUALT_VALIDITY_TIME);
- }
- /**
- * 增加緩存對象
- * @param key
- * @param ce
- * @param validityTime 有效時間
- */
- public static synchronized void addCache(String key, CacheEntity ce, int validityTime){
- map.put(key, ce);
- //添加過期定時
- timer.schedule(new TimeoutTimerTask(key), validityTime * SECOND_TIME);
- }
- /**
- * 獲取緩存對象
- * @param key
- * @return
- */
- public static synchronized CacheEntity getCache(String key){
- return map.get(key);
- }
- /**
- * 檢查是否含有制定key的緩沖
- * @param key
- * @return
- */
- public static synchronized boolean isConcurrent(String key){
- return map.containsKey(key);
- }
- /**
- * 刪除緩存
- * @param key
- */
- public static synchronized void removeCache(String key){
- map.remove(key);
- }
- /**
- * 獲取緩存大小
- * @param key
- */
- public static int getCacheSize(){
- return map.size();
- }
- /**
- * 清除全部緩存
- */
- public static synchronized void clearCache(){
- if(null != timer){
- timer.cancel();
- }
- map.clear();
- System.out.println("clear cache");
- }
- /**
- * @projName:WZServer
- * @className:TimeoutTimerTask
- * @description:清除超時緩存定時服務類
- * @creater:Administrator
- * @creatTime:2013年7月22日 上午9:34:39
- * @alter:Administrator
- * @alterTime:2013年7月22日 上午9:34:39
- * @remark:
- * @version
- */
- static class TimeoutTimerTask extends TimerTask{
- private String ceKey ;
- public TimeoutTimerTask(String key){
- this.ceKey = key;
- }
- @Override
- public void run() {
- CacheTimerHandler.removeCache(ceKey);
- System.out.println("remove : "+ceKey);
- }
- }
- }
timer方式有點是適用性更強,因為每個緩存的過期時間都可以獨立配置的;ist只能適用於緩存時間都一樣的線性過期。從性能開銷方面,因為timer是與緩存對象數量成正比的,在緩存量很大的時候,在緩存時間內系統開銷也隨之提高;而list方式只要一個線程管理過期清理就可以了。
這里要感謝飯飯泛,從其微博學習到很多http://www.blogjava.net/xylz/archive/2010/07/14/326080.html
對timer方式的改進,定時程序只需要一個就可以了,過期時間,通過一個對象保存,根據每個對象的過期時間判斷是否移除該緩存。於是得到下面的版本:
package com.cttc.cache.handler; import java.util.HashMap; import java.util.Map; import java.util.Timer; import java.util.TimerTask; /** * 在緩存的時候,同時記錄下該key,緩存時間,失效周期 * 在讀取緩存的時候,更新該key的緩存時間, * 定時器每兩個小時運行一次,檢查每個key是否過期,如果過期,刪除Jboss中的cache * */ public class CacheTimerMamager{ private static final long SECOND_TIME = 1000;//毫秒 private static final long DEFUALT_VALIDITY_TIME = SECOND_TIME * 60 * 60 * 2;//默認過期時間 :2小時 private static final Timer timer ; private static final Map<String, CacheOutTime> map; static{ timer = new Timer(); map = new HashMap<String, CacheOutTime>(); timer.schedule(new CacheTimerTask(), DEFUALT_VALIDITY_TIME, DEFUALT_VALIDITY_TIME); } /** * 增加緩存對象 * @param key * @param ce */ public static synchronized void addCache(String key){ CacheOutTime cot = map.get(key); long outTime = System.currentTimeMillis()+DEFUALT_VALIDITY_TIME; if(cot==null){ cot = new CacheOutTime(key, outTime); map.put(key, cot); }else{ //更新該key的過期時間 cot.setTimeoutStamp(outTime); } } //移除cache /** * 考慮,在多線程時,當有線程已經取得緩存對象時,刪掉了緩存,會產生什么情況 */ public static synchronized void removeCache() { CacheOutTime cot; long currentTime = System.currentTimeMillis(); for (String key : map.keySet()) { cot = map.get(key); if(cot.getTimeoutStamp()<=currentTime){ System.out.println("remove : "+key); } } } static class CacheTimerTask extends TimerTask{ @Override public void run() { //移除cache CacheTimerMamager.removeCache(); } } } class CacheOutTime { private String cacheKey; private long timeoutStamp;//過期時間戳,在最后一次訪問該key的時候計算得到 public CacheOutTime() { super(); } public CacheOutTime(String cacheKey, long timeoutStamp) { super(); this.cacheKey = cacheKey; this.timeoutStamp = timeoutStamp; } public String getCacheKey() { return cacheKey; } public void setCacheKey(String cacheKey) { this.cacheKey = cacheKey; } public long getTimeoutStamp() { return timeoutStamp; } public void setTimeoutStamp(long timeoutStamp) { this.timeoutStamp = timeoutStamp; } }
package com.cttc.cache.handler;
import java.util.HashMap;import java.util.Map;import java.util.Timer;import java.util.TimerTask;/** * 在緩存的時候,同時記錄下該key,緩存時間,失效周期 * 在讀取緩存的時候,更新該key的緩存時間, * 定時器每兩個小時運行一次,檢查每個key是否過期,如果過期,刪除Jboss中的cache * */public class CacheTimerMamager{private static final long SECOND_TIME = 1000;//毫秒private static final long DEFUALT_VALIDITY_TIME = SECOND_TIME * 60 * 60 * 2;//默認過期時間 :2小時private static final Timer timer ;private static final Map<String, CacheOutTime> map;static{timer = new Timer();map = new HashMap<String, CacheOutTime>();timer.schedule(new CacheTimerTask(), DEFUALT_VALIDITY_TIME, DEFUALT_VALIDITY_TIME);}/** * 增加緩存對象 * @param key * @param ce */public static synchronized void addCache(String key){CacheOutTime cot = map.get(key);long outTime = System.currentTimeMillis()+DEFUALT_VALIDITY_TIME;if(cot==null){cot = new CacheOutTime(key, outTime);map.put(key, cot);}else{//更新該key的過期時間cot.setTimeoutStamp(outTime);}}//移除cache/** * 考慮,在多線程時,當有線程已經取得緩存對象時,刪掉了緩存,會產生什么情況 */public static synchronized void removeCache() {CacheOutTime cot;long currentTime = System.currentTimeMillis();for (String key : map.keySet()) {cot = map.get(key);if(cot.getTimeoutStamp()<=currentTime){System.out.println("remove : "+key);}}}static class CacheTimerTask extends TimerTask{@Overridepublic void run() {//移除cacheCacheTimerMamager.removeCache();}}}
class CacheOutTime {private String cacheKey;private long timeoutStamp;//過期時間戳,在最后一次訪問該key的時候計算得到public CacheOutTime() {super();}public CacheOutTime(String cacheKey, long timeoutStamp) {super();this.cacheKey = cacheKey;this.timeoutStamp = timeoutStamp;}public String getCacheKey() {return cacheKey;}public void setCacheKey(String cacheKey) {this.cacheKey = cacheKey;}public long getTimeoutStamp() {return timeoutStamp;}public void setTimeoutStamp(long timeoutStamp) {this.timeoutStamp = timeoutStamp;}}