zoukankan      html  css  js  c++  java
  • 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;}}

  • 相关阅读:
    二分思想判断数组中是否有两数和为sum
    VC中#pragma warning指令
    (转)预编译头文件
    成为一名优秀程序员所需要知道的那些事
    SetThreadAffinityMask设置使用多核CPU的哪个核心
    DirectX 3D 设备丢失(lost device)的处理
    转载 CreateWaitableTimer和SetWaitableTimer函数
    转赵青《剑侠情缘网络版》开发回顾
    转载使用PostThreadMessage在Win32线程间传递消息
    VC使用CRT调试功能检测内存泄漏
  • 原文地址:https://www.cnblogs.com/firstdream/p/5515090.html
Copyright © 2011-2022 走看看