<address id="ousso"></address>
<form id="ousso"><track id="ousso"><big id="ousso"></big></track></form>
  1. java語言

    Java如何實現一個簡單的緩存

    時間:2025-04-13 20:10:32 java語言 我要投稿
    • 相關推薦

    Java如何實現一個簡單的緩存

      緩存是在web開發中經常用到的,將程序經常使用到或調用到的對象存在內存中,或者是耗時較長但又不具有實時性的查詢數據放入內存中,在一定程度上可以提高性能和效率。那么,用Java如何實現一個簡單的緩存?下面百分網小編帶大家一起來看看詳細內容,希望對大家有所幫助!想了解更多相關信息請持續關注我們應屆畢業生考試網!

      創建緩存對象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());

      }

      }

      testCacheManager()輸出結果如下:

      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()輸出結果如下(選出了各種結果中的一個舉例):

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

      信息: 96

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

      if (!cacheManagerImpl.isContains(key)) {

      cacheManagerImpl.putCache(key, 1, 0);

      }

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

    【Java如何實現一個簡單的緩存】相關文章:

    Java 中常用緩存Cache機制的實現08-27

    java的緩存機制07-29

    java的緩存機制簡介09-06

    php頁面緩存實現方法07-20

    java如何實現漢諾塔08-08

    Java 隊列實現原理及簡單實現代碼09-13

    java通用組合算法如何實現09-12

    Java中如何實現顯示動態的時間09-28

    如何在java中實現左右鍵菜單10-30

    <address id="ousso"></address>
    <form id="ousso"><track id="ousso"><big id="ousso"></big></track></form>
    1. 日日做夜狠狠爱欧美黑人