java cache過期策略兩種實現,一個基於list輪詢一個基於timer定時


       最近項目要引入緩存機制,但是不想引入分布式的緩存框架,所以自己就寫了一個輕量級的緩存實現,有兩個版本,一個是通過timer實現其超時過期處理,另外一個是通過list輪詢。
       首先要了解下java1.6中的ConcurrentMap ,他是一個線程安全的Map實現,特別說明的是在沒有特別需求的情況下可以用ConcurrentHashMap。我是想學習一下讀寫鎖的應用,就自己實現了一個SimpleConcurrentHashMap.

[java]  view plain  copy
 
 print?
  1. package com.cttc.cache.entity;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collection;  
  5. import java.util.HashSet;  
  6. import java.util.Map;  
  7. import java.util.Set;  
  8. import java.util.concurrent.locks.Lock;  
  9. import java.util.concurrent.locks.ReadWriteLock;  
  10. import java.util.concurrent.locks.ReentrantReadWriteLock;  
  11.   
  12. public class SimpleConcurrentMap<K, V> implements Map<K, V> {  
  13.     final ReadWriteLock lock = new ReentrantReadWriteLock();  
  14.     final Lock r = lock.readLock();  
  15.     final Lock w = lock.writeLock();  
  16.     final Map<K, V> map;  
  17.       
  18.     public SimpleConcurrentMap(Map<K, V> map) {  
  19.         this.map = map;  
  20.         if (map == null) throw new NullPointerException();  
  21.     }  
  22.   
  23.     public void clear() {  
  24.         w.lock();  
  25.         try {  
  26.             map.clear();  
  27.         } finally {  
  28.             w.unlock();  
  29.         }  
  30.     }  
  31.   
  32.     public boolean containsKey(Object key) {  
  33.         r.lock();  
  34.         try {  
  35.             return map.containsKey(key);  
  36.         } finally {  
  37.             r.unlock();  
  38.         }  
  39.     }  
  40.   
  41.     public boolean containsValue(Object value) {  
  42.         r.lock();  
  43.         try {  
  44.             return map.containsValue(value);  
  45.         } finally {  
  46.             r.unlock();  
  47.         }  
  48.     }  
  49.   
  50.     public Set<java.util.Map.Entry<K, V>> entrySet() {  
  51.         throw new UnsupportedOperationException();  
  52.     }  
  53.   
  54.     public V get(Object key) {  
  55.         r.lock();  
  56.         try {  
  57.             return map.get(key);  
  58.         } finally {  
  59.             r.unlock();  
  60.         }  
  61.     }  
  62.   
  63.     public boolean isEmpty() {  
  64.         r.lock();  
  65.         try {  
  66.             return map.isEmpty();  
  67.         } finally {  
  68.             r.unlock();  
  69.         }  
  70.     }  
  71.   
  72.     public Set<K> keySet() {  
  73.         r.lock();  
  74.         try {  
  75.             return new HashSet<K>(map.keySet());  
  76.         } finally {  
  77.             r.unlock();  
  78.         }  
  79.     }  
  80.   
  81.     public V put(K key, V value) {  
  82.         w.lock();  
  83.         try {  
  84.             return map.put(key, value);  
  85.         } finally {  
  86.             w.unlock();  
  87.         }  
  88.     }  
  89.   
  90.     public void putAll(Map<? extends K, ? extends V> m) {  
  91.         w.lock();  
  92.         try {  
  93.             map.putAll(m);  
  94.         } finally {  
  95.             w.unlock();  
  96.         }  
  97.     }  
  98.   
  99.     public V remove(Object key) {  
  100.         w.lock();  
  101.         try {  
  102.             return map.remove(key);  
  103.         } finally {  
  104.             w.unlock();  
  105.         }  
  106.     }  
  107.   
  108.     public int size() {  
  109.         r.lock();  
  110.         try {  
  111.             return map.size();  
  112.         } finally {  
  113.             r.unlock();  
  114.         }  
  115.     }  
  116.   
  117.     public Collection<V> values() {  
  118.         r.lock();  
  119.         try {  
  120.             return new ArrayList<V>(map.values());  
  121.         } finally {  
  122.             r.unlock();  
  123.         }  
  124.     }  
  125.   
  126. }  


緩存對象CacheEntity.Java為:

[html]  view plain  copy
 
 print?
  1. package com.cttc.cache.entity;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class CacheEntity implements Serializable{  
  6.     private static final long serialVersionUID = -3971709196436977492L;  
  7.     private final int DEFUALT_VALIDITY_TIME = 20;//默認過期時間 20秒  
  8.       
  9.     private String cacheKey;  
  10.     private Object cacheContext;  
  11.     private int validityTime;//有效期時長,單位:秒  
  12.     private long timeoutStamp;//過期時間戳  
  13.       
  14.     private CacheEntity(){  
  15.         this.timeoutStamp = System.currentTimeMillis() + DEFUALT_VALIDITY_TIME * 1000;  
  16.         this.validityTime = DEFUALT_VALIDITY_TIME;  
  17.     }  
  18.       
  19.     public CacheEntity(String cacheKey, Object cacheContext){  
  20.         this();  
  21.         this.cacheKey = cacheKey;  
  22.         this.cacheContext = cacheContext;  
  23.     }  
  24.       
  25.     public CacheEntity(String cacheKey, Object cacheContext, long timeoutStamp){  
  26.         this(cacheKey, cacheContext);  
  27.         this.timeoutStamp = timeoutStamp;  
  28.     }  
  29.       
  30.     public CacheEntity(String cacheKey, Object cacheContext, int validityTime){  
  31.         this(cacheKey, cacheContext);  
  32.         this.validityTime = validityTime;  
  33.         this.timeoutStamp = System.currentTimeMillis() + validityTime * 1000;  
  34.     }  
  35.   
  36.     public String getCacheKey() {  
  37.         return cacheKey;  
  38.     }  
  39.     public void setCacheKey(String cacheKey) {  
  40.         this.cacheKey = cacheKey;  
  41.     }  
  42.     public Object getCacheContext() {  
  43.         return cacheContext;  
  44.     }  
  45.     public void setCacheContext(Object cacheContext) {  
  46.         this.cacheContext = cacheContext;  
  47.     }  
  48.     public long getTimeoutStamp() {  
  49.         return timeoutStamp;  
  50.     }  
  51.     public void setTimeoutStamp(long timeoutStamp) {  
  52.         this.timeoutStamp = timeoutStamp;  
  53.     }  
  54.     public int getValidityTime() {  
  55.         return validityTime;  
  56.     }  
  57.     public void setValidityTime(int validityTime) {  
  58.         this.validityTime = validityTime;  
  59.     }  
  60. }  


List緩存處理對象:

[java]  view plain  copy
 
 print?
  1. package com.cttc.cache.handler;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6.   
  7. import com.cttc.cache.entity.CacheEntity;  
  8. import com.cttc.cache.entity.SimpleConcurrentMap;  
  9.   
  10. /** 
  11.  * @projName:WZServer 
  12.  * @className:CacheHandler 
  13.  * @description:緩存操作類,對緩存進行管理,采用處理隊列,定時循環清理的方式 
  14.  * @creater:Administrator  
  15.  * @creatTime:2013年7月22日 上午9:18:54  
  16.  * @alter:Administrator 
  17.  * @alterTime:2013年7月22日 上午9:18:54   
  18.  * @remark: 
  19.  * @version  
  20.  */  
  21. public class CacheListHandler {  
  22.     private static final long SECOND_TIME = 1000;  
  23.     private static final SimpleConcurrentMap<String, CacheEntity> map;  
  24.     private static final List<CacheEntity> tempList;  
  25.       
  26.     static{  
  27.         tempList = new ArrayList<CacheEntity>();  
  28.         map = new SimpleConcurrentMap<String, CacheEntity>(new HashMap<String, CacheEntity>(1<<18));  
  29.         new Thread(new TimeoutTimerThread()).start();  
  30.     }  
  31.               
  32.     /** 
  33.      * 增加緩存對象 
  34.      * @param key 
  35.      * @param ce 
  36.      */  
  37.     public static void addCache(String key, CacheEntity ce){  
  38.         addCache(key, ce, ce.getValidityTime());  
  39.     }  
  40.       
  41.     /** 
  42.      * 增加緩存對象 
  43.      * @param key 
  44.      * @param ce 
  45.      * @param validityTime 有效時間 
  46.      */  
  47.     public static synchronized void addCache(String key, CacheEntity ce, int validityTime){  
  48.         ce.setTimeoutStamp(System.currentTimeMillis() + validityTime * SECOND_TIME);  
  49.         map.put(key, ce);  
  50.         //添加到過期處理隊列  
  51.         tempList.add(ce);  
  52.     }  
  53.       
  54.     /** 
  55.      * 獲取緩存對象 
  56.      * @param key 
  57.      * @return 
  58.      */  
  59.     public static synchronized CacheEntity getCache(String key){  
  60.         return map.get(key);  
  61.     }  
  62.       
  63.     /** 
  64.      * 檢查是否含有制定key的緩沖 
  65.      * @param key 
  66.      * @return 
  67.      */  
  68.     public static synchronized boolean isConcurrent(String key){  
  69.         return map.containsKey(key);  
  70.     }  
  71.       
  72.     /** 
  73.      * 刪除緩存 
  74.      * @param key 
  75.      */  
  76.     public static synchronized void removeCache(String key){  
  77.         map.remove(key);  
  78.     }  
  79.       
  80.     /** 
  81.      * 獲取緩存大小 
  82.      * @param key 
  83.      */  
  84.     public static int getCacheSize(){  
  85.         return map.size();  
  86.     }  
  87.       
  88.     /** 
  89.      * 清除全部緩存 
  90.      */  
  91.     public static synchronized void clearCache(){  
  92.         tempList.clear();  
  93.         map.clear();  
  94.         System.out.println("clear cache");  
  95.     }  
  96.       
  97.     static class TimeoutTimerThread implements Runnable {  
  98.         public void run(){  
  99.             while(true){  
  100.                 try {  
  101.                     checkTime();  
  102.                 } catch (Exception e) {  
  103.                     e.printStackTrace();  
  104.                 }  
  105.             }  
  106.         }  
  107.           
  108.         /** 
  109.          * 過期緩存的具體處理方法 
  110.          * @throws Exception 
  111.          */  
  112.         private void checkTime() throws Exception{    
  113.             //"開始處理過期 ";  
  114.             CacheEntity tce = null;  
  115.             long timoutTime = 1000L;  
  116.               
  117.             //" 過期隊列大小 : "+tempList.size());  
  118.             if(1 > tempList.size()){  
  119.                 System.out.println("過期隊列空,開始輪詢");  
  120.                 timoutTime = 1000L;  
  121.                 Thread.sleep(timoutTime);  
  122.                 return;  
  123.             }  
  124.               
  125.             tce = tempList.get(0);  
  126.             timoutTime = tce.getTimeoutStamp() - System.currentTimeMillis();  
  127.             //" 過期時間 : "+timoutTime);  
  128.             if(0 < timoutTime){  
  129.                 //設定過期時間  
  130.                 Thread.sleep(timoutTime);  
  131.                 return;  
  132.             }  
  133.             System.out.print(" 清除過期緩存 : "+tce.getCacheKey());  
  134.             //清除過期緩存和刪除對應的緩存隊列  
  135.             tempList.remove(tce);  
  136.             removeCache(tce.getCacheKey());  
  137.         }  
  138.     }  
  139. }  


Timer方式

[java]  view plain  copy
 
 print?
  1. package com.cttc.cache.handler;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Timer;  
  5. import java.util.TimerTask;  
  6.   
  7. import com.cttc.cache.entity.CacheEntity;  
  8. import com.cttc.cache.entity.SimpleConcurrentMap;  
  9.   
  10. /** 
  11.  * @projName:WZServer 
  12.  * @className:CacheHandler 
  13.  * @description:緩存操作類,對緩存進行管理,清除方式采用Timer定時的方式 
  14.  * @creater:Administrator  
  15.  * @creatTime:2013年7月22日 上午9:18:54  
  16.  * @alter:Administrator 
  17.  * @alterTime:2013年7月22日 上午9:18:54   
  18.  * @remark: 
  19.  * @version  
  20.  */  
  21. public class CacheTimerHandler {  
  22.     private static final long SECOND_TIME = 1000;//默認過期時間 20秒  
  23.     private static final int DEFUALT_VALIDITY_TIME = 20;//默認過期時間 20秒  
  24.     private static final Timer timer ;  
  25.     private static final SimpleConcurrentMap<String, CacheEntity> map;  
  26.       
  27.     static{  
  28.         timer = new Timer();  
  29.         map = new SimpleConcurrentMap<String, CacheEntity>(new HashMap<String, CacheEntity>(1<<18));  
  30.     }  
  31.               
  32.     /** 
  33.      * 增加緩存對象 
  34.      * @param key 
  35.      * @param ce 
  36.      */  
  37.     public static void addCache(String key, CacheEntity ce){  
  38.         addCache(key, ce, DEFUALT_VALIDITY_TIME);  
  39.     }  
  40.       
  41.     /** 
  42.      * 增加緩存對象 
  43.      * @param key 
  44.      * @param ce 
  45.      * @param validityTime 有效時間 
  46.      */  
  47.     public static synchronized void addCache(String key, CacheEntity ce, int validityTime){  
  48.         map.put(key, ce);  
  49.         //添加過期定時  
  50.         timer.schedule(new TimeoutTimerTask(key), validityTime * SECOND_TIME);  
  51.     }  
  52.       
  53.     /** 
  54.      * 獲取緩存對象 
  55.      * @param key 
  56.      * @return 
  57.      */  
  58.     public static synchronized CacheEntity getCache(String key){  
  59.         return map.get(key);  
  60.     }  
  61.       
  62.     /** 
  63.      * 檢查是否含有制定key的緩沖 
  64.      * @param key 
  65.      * @return 
  66.      */  
  67.     public static synchronized boolean isConcurrent(String key){  
  68.         return map.containsKey(key);  
  69.     }  
  70.       
  71.     /** 
  72.      * 刪除緩存 
  73.      * @param key 
  74.      */  
  75.     public static synchronized void removeCache(String key){  
  76.         map.remove(key);  
  77.     }  
  78.       
  79.     /** 
  80.      * 獲取緩存大小 
  81.      * @param key 
  82.      */  
  83.     public static int getCacheSize(){  
  84.         return map.size();  
  85.     }  
  86.       
  87.     /** 
  88.      * 清除全部緩存 
  89.      */  
  90.     public static synchronized void clearCache(){  
  91.         if(null != timer){  
  92.             timer.cancel();  
  93.         }  
  94.         map.clear();  
  95.         System.out.println("clear cache");  
  96.     }  
  97.       
  98.     /** 
  99.      * @projName:WZServer 
  100.      * @className:TimeoutTimerTask 
  101.      * @description:清除超時緩存定時服務類 
  102.      * @creater:Administrator  
  103.      * @creatTime:2013年7月22日 上午9:34:39  
  104.      * @alter:Administrator 
  105.      * @alterTime:2013年7月22日 上午9:34:39   
  106.      * @remark: 
  107.      * @version  
  108.      */  
  109.     static class TimeoutTimerTask extends TimerTask{  
  110.         private String ceKey ;  
  111.           
  112.         public TimeoutTimerTask(String key){  
  113.             this.ceKey = key;  
  114.         }  
  115.   
  116.         @Override  
  117.         public void run() {  
  118.             CacheTimerHandler.removeCache(ceKey);  
  119.             System.out.println("remove : "+ceKey);  
  120.         }  
  121.     }  
  122. }  


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;}}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM