Java實現一個簡單的緩存方法


緩存是在web開發中經常用到的,將程序經常使用到或調用到的對象存在內存中,或者是耗時較長但又不具有實時性的查詢數據放入內存中,在一定程度上可以提高性能和效率。下面我實現了一個簡單的緩存,步驟如下。

創建緩存對象EntityCache.java

public class EntityCache {
   /**
    * 保存的數據
    */
   private Object datas;
 
   /**
    * 設置數據失效時間,為0表示永不失效
    */
   private long timeOut;
 
   /**
    * 最后刷新時間
    */
   private long lastRefeshTime;
 
   public EntityCache(Object datas, long timeOut, long lastRefeshTime) {
     this .datas = datas;
     this .timeOut = timeOut;
     this .lastRefeshTime = lastRefeshTime;
   }
   public Object getDatas() {
     return datas;
   }
   public void setDatas(Object datas) {
     this .datas = datas;
   }
   public long getTimeOut() {
     return timeOut;
   }
   public void setTimeOut( long timeOut) {
     this .timeOut = timeOut;
   }
   public long getLastRefeshTime() {
     return lastRefeshTime;
   }
   public void setLastRefeshTime( long lastRefeshTime) {
     this .lastRefeshTime = lastRefeshTime;
   }
 
 
}
定義緩存操作接口,ICacheManager.java
public interface ICacheManager {
   /**
    * 存入緩存
    * @param key
    * @param cache
    */
   void putCache(String key, EntityCache cache);
 
   /**
    * 存入緩存
    * @param key
    * @param cache
    */
   void putCache(String key, Object datas, long timeOut);
 
   /**
    * 獲取對應緩存
    * @param key
    * @return
    */
   EntityCache getCacheByKey(String key);
 
   /**
    * 獲取對應緩存
    * @param key
    * @return
    */
   Object getCacheDataByKey(String key);
 
   /**
    * 獲取所有緩存
    * @param key
    * @return
    */
   Map<String, EntityCache> getCacheAll();
 
   /**
    * 判斷是否在緩存中
    * @param key
    * @return
    */
   boolean isContains(String key);
 
   /**
    * 清除所有緩存
    */
   void clearAll();
 
   /**
    * 清除對應緩存
    * @param key
    */
   void clearByKey(String key);
 
   /**
    * 緩存是否超時失效
    * @param key
    * @return
    */
   boolean isTimeOut(String key);
 
   /**
    * 獲取所有key
    * @return
    */
   Set<String> getAllKeys();
}

實現接口ICacheManager,CacheManagerImpl.java

這里我使用了ConcurrentHashMap來保存緩存,本來以為這樣就是線程安全的,其實不然,在后面的測試中會發現它並不是線程安全的。

public class CacheManagerImpl implements ICacheManager {
   private static Map<String, EntityCache> caches = new ConcurrentHashMap<String, EntityCache>();
 
   /**
    * 存入緩存
    * @param key
    * @param cache
    */
   public void putCache(String key, EntityCache cache) {
     caches.put(key, cache);
   }
 
   /**
    * 存入緩存
    * @param key
    * @param cache
    */
   public void putCache(String key, Object datas, long timeOut) {
     timeOut = timeOut > 0 ? timeOut : 0L;
     putCache(key, new EntityCache(datas, timeOut, System.currentTimeMillis()));
   }
 
   /**
    * 獲取對應緩存
    * @param key
    * @return
    */
   public EntityCache getCacheByKey(String key) {
     if ( this .isContains(key)) {
       return caches.get(key);
     }
     return null ;
   }
 
   /**
    * 獲取對應緩存
    * @param key
    * @return
    */
   public Object getCacheDataByKey(String key) {
     if ( this .isContains(key)) {
       return caches.get(key).getDatas();
     }
     return null ;
   }
 
   /**
    * 獲取所有緩存
    * @param key
    * @return
    */
   public Map<String, EntityCache> getCacheAll() {
     return caches;
   }
 
   /**
    * 判斷是否在緩存中
    * @param key
    * @return
    */
   public boolean isContains(String key) {
     return caches.containsKey(key);
   }
 
   /**
    * 清除所有緩存
    */
   public void clearAll() {
     caches.clear();
   }
 
   /**
    * 清除對應緩存
    * @param key
    */
   public void clearByKey(String key) {
     if ( this .isContains(key)) {
       caches.remove(key);
     }
   }
 
   /**
    * 緩存是否超時失效
    * @param key
    * @return
    */
   public boolean isTimeOut(String key) {
     if (!caches.containsKey(key)) {
       return true ;
     }
     EntityCache cache = caches.get(key);
     long timeOut = cache.getTimeOut();
     long lastRefreshTime = cache.getLastRefeshTime();
     if (timeOut == 0 || System.currentTimeMillis() - lastRefreshTime >= timeOut) {
       return true ;
     }
     return false ;
   }
 
   /**
    * 獲取所有key
    * @return
    */
   public Set<String> getAllKeys() {
     return caches.keySet();
   }
}
CacheListener.java,監聽失效數據並移除。
public class CacheListener{
   Logger logger = Logger.getLogger( "cacheLog" );
   private CacheManagerImpl cacheManagerImpl;
   public CacheListener(CacheManagerImpl cacheManagerImpl) {
     this .cacheManagerImpl = cacheManagerImpl;
   }
 
   public void startListen() {
     new Thread(){
       public void run() {
         while ( true ) {
           for (String key : cacheManagerImpl.getAllKeys()) {
             if (cacheManagerImpl.isTimeOut(key)) {
              cacheManagerImpl.clearByKey(key);
              logger.info(key + "緩存被清除" );
            }
           }
         }
       }
     }.start();
 
   }
}
測試類TestCache.java
public class TestCache {
   Logger logger = Logger.getLogger( "cacheLog" );
   /**
    * 測試緩存和緩存失效
    */
   @Test
   public void testCacheManager() {
     CacheManagerImpl cacheManagerImpl = new CacheManagerImpl();
     cacheManagerImpl.putCache( "test" , "test" , 10 * 1000L);
     cacheManagerImpl.putCache( "myTest" , "myTest" , 15 * 1000L);
     CacheListener cacheListener = new CacheListener(cacheManagerImpl);
     cacheListener.startListen();
     logger.info( "test:" + cacheManagerImpl.getCacheByKey( "test" ).getDatas());
     logger.info( "myTest:" + cacheManagerImpl.getCacheByKey( "myTest" ).getDatas());
     try {
       TimeUnit.SECONDS.sleep( 20 );
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
     logger.info( "test:" + cacheManagerImpl.getCacheByKey( "test" ));
     logger.info( "myTest:" + cacheManagerImpl.getCacheByKey( "myTest" ));
   }
 
   /**
    * 測試線程安全
    */
   @Test
   public void testThredSafe() {
     final String key = "thread" ;
     final CacheManagerImpl cacheManagerImpl = new CacheManagerImpl();
     ExecutorService exec = Executors.newCachedThreadPool();
     for ( int i = 0 ; i < 100 ; i++) {
       exec.execute( new Runnable() {
         public void run() {
             if (!cacheManagerImpl.isContains(key)) {
               cacheManagerImpl.putCache(key, 1 , 0 );
             } else {
               //因為+1和賦值操作不是原子性的,所以把它用synchronize塊包起來
               synchronized (cacheManagerImpl) {
                 int value = (Integer) cacheManagerImpl.getCacheDataByKey(key) + 1 ;
                 cacheManagerImpl.putCache(key,value , 0 );
               }
             }
         }
       });
     }
     exec.shutdown();
     try {
       exec.awaitTermination( 1 , TimeUnit.DAYS);
     } catch (InterruptedException e1) {
       e1.printStackTrace();
     }
 
     logger.info(cacheManagerImpl.getCacheDataByKey(key).toString());
   }
}
 
 
來源:http://www.jb51.net/article/111518.htm


免責聲明!

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



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