缓存是在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

Java实现一个简单的缓存方法的更多相关文章

  1. 哪种缓存效果高?开源一个简单的缓存组件j2cache

    背景 现在的web系统已经越来越多的应用缓存技术,而且缓存技术确实是能实足的增强系统性能的.我在项目中也开始接触一些缓存的需求. 开始简单的就用jvm(java托管内存)来做缓存,这样对于单个应用服务 ...

  2. 使用Java编写一个简单的Web的监控系统cpu利用率,cpu温度,总内存大小

    原文:http://www.jb51.net/article/75002.htm 这篇文章主要介绍了使用Java编写一个简单的Web的监控系统的例子,并且将重要信息转为XML通过网页前端显示,非常之实 ...

  3. Java实现一个简单的文件上传案例

    Java实现一个简单的文件上传案例 实现流程: 1.客户端从硬盘读取文件数据到程序中 2.客户端输出流,写出文件到服务端 3.服务端输出流,读取文件数据到服务端中 4.输出流,写出文件数据到服务器硬盘 ...

  4. 只是一个用EF写的一个简单的分页方法而已

    只是一个用EF写的一个简单的分页方法而已 慢慢的写吧.比如,第一步,先把所有数据查询出来吧. //第一步. public IQueryable<UserInfo> LoadPagesFor ...

  5. 使用 java 实现一个简单的 markdown 语法解析器

    1. 什么是 markdown Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用.看到这里请不要被「标记」.「语言」所迷惑,Markdown 的 ...

  6. java:jsp: 一个简单的自定义标签 tld

    java:jsp: 一个简单的自定义标签 tld 请注意,uri都是:http://www.tag.com/mytag,保持统一,要不然报错,不能访问 tld文件 <?xml version=& ...

  7. js new一个对象的过程,实现一个简单的new方法

    对于大部分前端开发者而言,new一个构造函数或类得到对应实例,是非常普遍的操作了.下面的例子中分别通过构造函数与class类实现了一个简单的创建实例的过程. // ES5构造函数 let Parent ...

  8. 使用JAVA写一个简单的日历

    JAVA写一个简单的日历import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateF ...

  9. Java实现一个简单的网络爬虫

    Java实现一个简单的网络爬虫 import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWri ...

随机推荐

  1. python学习笔记——

    python线程的GIL GIL (全局解释器锁)python --- > 支持多线程 ----> 同步和互斥 --->加锁 --->解释器加锁 ————> 解释器同一时 ...

  2. Shell习题100例(2)

    找文件差异 grep -f 选项可以匹配到文件a在文件b中所有相关的行(取a中有b中有的) [root@centos-04 tmp]# vim b.txt vvvv root [root@centos ...

  3. Python abs() 函数

    描述 abs() 函数返回数字的绝对值. 语法 以下是 abs() 方法的语法: abs( x ) 参数 x -- 数值表达式,可以是整数,浮点数,复数. 返回值 函数返回 x(数字)的绝对值,如果参 ...

  4. bs-web项目时会经常打断点跟踪信息,可是循环时总是F10、F10的按,那么把所数据打印出来查看会更方便

    bs-web项目时会经常打断点跟踪信息,可是循环时总是F10.F10的按,那么把所数据打印出来查看会更方便 一.打断点的方式适合在有错误产生的时候用很好用. 二.可是在分析数据时不直观,得一个一个循环 ...

  5. unity5 Edit Collider

    按下Edit Collider按钮,视图中Collider线框中出现控制点,可以通过拖动控制点对Collider进行调整.

  6. Install Ambari 2.2.0 from Public Repositories(Hadoop)

    Step1: Download the Ambari repository on the Ambari Server host For Redhat/CentOS/Oracle:   cd /etc/ ...

  7. Java:集合,对列表(List)中的数据(整型、字符串、日期等)进行排序(正序、倒序)的方法;字符串按照整型排序的方法

    1. 要求 对List列表中的数据进行排序(正序.倒序),列表中的数据包括:整型(Integer).字符串(String).日期(Date)等.对于字符串,要求允许对它按照整型进行排序. 2. 实现思 ...

  8. 已有iptables表的查看

    查看已有iptables表 iptables -L -nv --line-number-L是--list的简写,作用是列出规则-n是ip以数字方式显示,有的会用域名方式显示.-v是显示详细信息 v=v ...

  9. PHP遍历目录返回统计目录大小实例

    分享一个 PHP遍历目录并返回统计目录大小的方法.代码: <?php $dirname = "test1"; //mkdir($dirname); //遍历一层目录 func ...

  10. [na]那些OVER的封装(pppoe/ppp/ipsec)

    什么over什么,如pppoe, ppp的封装都在over对象之后,入下图: PPPOE Ipsec