• 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
  • 相关阅读:
    this指向
    this指向
    this指向
    this指向
    a=b=c 连等赋值的分析
    测试应用documentFragment 和 直接操作dom 的区别
    javascript 基本数据类型、引用数据类型
    判断一个变量的具体类型 的终极方案
    判断变量是否为 NaN
    C#稳固基础:传统遍历与迭代器
  • 原文地址:https://www.cnblogs.com/kongxc/p/8541930.html
Copyright © 2020-2023  润新知