欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實現(xiàn)一個簡單的緩存方法

 更新時間:2017年04月19日 09:23:41   作者:BrightLoong  
本篇文章主要介紹了Java實現(xiàn)一個簡單的緩存方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

創(chuàng)建緩存對象EntityCache.java

public class EntityCache {
  /**
   * 保存的數(shù)據(jù)
   */
  private Object datas;

  /**
   * 設(shè)置數(shù)據(jù)失效時間,為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();
}

實現(xiàn)接口ICacheManager,CacheManagerImpl.java

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

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,失效數(shù)據(jù)并移除。

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

testCacheManager()輸出結(jié)果如下:

2017-4-17 10:33:51 io.github.brightloong.cache.TestCache testCacheManager
信息: test:test
2017-4-17 10:33:51 io.github.brightloong.cache.TestCache testCacheManager
信息: myTest:myTest
2017-4-17 10:34:01 io.github.brightloong.cache.CacheListener$1 run
信息: test緩存被清除
2017-4-17 10:34:06 io.github.brightloong.cache.CacheListener$1 run
信息: myTest緩存被清除
2017-4-17 10:34:11 io.github.brightloong.cache.TestCache testCacheManager
信息: test:null
2017-4-17 10:34:11 io.github.brightloong.cache.TestCache testCacheManager
信息: myTest:null

testThredSafe()輸出結(jié)果如下(選出了各種結(jié)果中的一個舉例):

2017-4-17 10:35:36 io.github.brightloong.cache.TestCache testThredSafe
信息: 96

可以看到并不是預期的結(jié)果100,為什么呢?ConcurrentHashMap只能保證單次操作的原子性,但是當復合使用的時候,沒辦法保證復合操作的原子性,以下代碼:

if (!cacheManagerImpl.isContains(key)) {
              cacheManagerImpl.putCache(key, 1, 0);
            }

多線程的時候回重復更新value,設(shè)置為1,所以出現(xiàn)結(jié)果不是預期的100。所以辦法就是在CacheManagerImpl.java中都加上synchronized,但是這樣一來相當于操作都是串行,使用ConcurrentHashMap也沒有什么意義,不過只是簡單的緩存還是可以的。或者對測試方法中的run里面加上synchronized塊也行,都是大同小異。更高效的方法我暫時也想不出來,希望大家能多多指教。

相關(guān)文章

  • java實現(xiàn)省市區(qū)三級聯(lián)動

    java實現(xiàn)省市區(qū)三級聯(lián)動

    這篇文章主要為大家詳細介紹了java實現(xiàn)省市區(qū)三級聯(lián)動,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • springboot接口參數(shù)校驗JSR303的實現(xiàn)

    springboot接口參數(shù)校驗JSR303的實現(xiàn)

    本文主要介紹了springboot接口參數(shù)校驗JSR303的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • 概述Java的struts2框架

    概述Java的struts2框架

    本篇文章主要對struts2框架概念、優(yōu)缺點進行簡要概述。相信會對大家學習Java有所幫助,需要的朋友一起來看下吧
    2016-12-12
  • Lombok的@CustomLog流暢的公司多場景日志

    Lombok的@CustomLog流暢的公司多場景日志

    這篇文章主要為大家介紹了Lombok的@CustomLog流暢的公司多場景日志開發(fā)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Jackson使用示例-Bean、XML、Json之間相互轉(zhuǎn)換

    Jackson使用示例-Bean、XML、Json之間相互轉(zhuǎn)換

    Jackson是一個強大工具,可用于Json、XML、實體之間的相互轉(zhuǎn)換,JacksonXmlElementWrapper用于指定List等集合類,外圍標簽名,JacksonXmlProperty指定包裝標簽名,或者指定標簽內(nèi)部屬性名,JacksonXmlRootElement指定生成xml根標簽的名字,JacksonXmlText指定當前這個值
    2024-05-05
  • Java中toString函數(shù)的使用示例代碼

    Java中toString函數(shù)的使用示例代碼

    toString()函數(shù)用于將當前對象以字符串的形式返回,比如我定義了一個User類,創(chuàng)建了一個user對象,然后使用相應命令去打印user對象,本文結(jié)合示例代碼介紹了toString函數(shù)的使用,需要的朋友可以參考下
    2024-02-02
  • 混亂的Java日志體系及集成jar包梳理分析

    混亂的Java日志體系及集成jar包梳理分析

    這篇文章主要詳細的為大家梳理分析了剪不斷理還亂的Java日志體系,以及日志系統(tǒng)涉及到的繁雜的各種集成?jar?包,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-03-03
  • 基于SpringBoot啟動類靜態(tài)資源路徑問題

    基于SpringBoot啟動類靜態(tài)資源路徑問題

    這篇文章主要介紹了SpringBoot啟動類靜態(tài)資源路徑問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java 二進制數(shù)據(jù)與16進制字符串相互轉(zhuǎn)化方法

    java 二進制數(shù)據(jù)與16進制字符串相互轉(zhuǎn)化方法

    今天小編就為大家分享一篇java 二進制數(shù)據(jù)與16進制字符串相互轉(zhuǎn)化方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • Springcloud ribbon負載均衡算法實現(xiàn)

    Springcloud ribbon負載均衡算法實現(xiàn)

    這篇文章主要介紹了Springcloud ribbon負載均衡算法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04

最新評論