Java实现一个简单的缓存方法

发布时间:2020-09-07 21:39:55

来源:脚本之家

阅读:99

作者:BrightLoong

缓存是在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 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 getAllKeys();

}

实现接口ICacheManager,CacheManagerImpl.java

这里我使用了ConcurrentHashMap来保存缓存,本来以为这样就是线程安全的,其实不然,在后面的测试中会发现它并不是线程安全的。

public class CacheManagerImpl implements ICacheManager {

private static Map caches = new ConcurrentHashMap();

/**

* 存入缓存

* @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 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 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实现一个简单的缓存方法相关推荐

  1. java编写服务器_java编写一个简单的回射服务器

    全部代码 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; im ...

  2. java实现堆栈_Java实现一个简单的堆栈

    堆栈(Stack)是一种常见的数据结构,符合后进先出(First In Last Out)原则,通常用于实现对象存放顺序的逆序.栈的基本操作有push(添加到堆栈),pop(从堆栈删除),peek(检 ...

  3. java五子棋盘_Java实现一个简单的两人五子棋游戏(二) 画棋盘

    棋盘模块: 画五子棋棋盘:19条横线.19条竖线 步骤一:显示棋盘 我有一张名为chessboard.png的棋盘,位置为根目录/res/drawable/chessboard/png,现在我要显示这 ...

  4. 将Java程序变成可执行文件的一个简单方法

    将Java程序变成可执行文件的一个简单方法 运行Java程序(SWING或SWT的桌面程序)可以直接执行.class文件或将所有的.class文件及相关的其他文件压缩成.jar文件,然后使用javaw ...

  5. java 随机数生成实现_Java中生成随机数的实现方法总结

    搜索热词 在实际开发工作中经常需要用到随机数.如有些系统中创建用户后会给用户一个随机的初始化密码.这个密码由于是随机的,为此往往只有用户自己知道.他们获取了这个随机密码之后,需要马上去系统中更改.这就 ...

  6. java定义负数_java定义一个负数

    提示: InsufficientFundsException,NagativeFundsException 为自定义的类,分别产生余额不足异 常和取款为负数异常,需继承 Exception 类. 通过 ...

  7. hibernate二级缓存(三) 自定义实现一个简单的hibernate二级缓存

    hibernate二级缓存(三) 自定义实现一个简单的hibernate二级缓存 前面我们已经提及过hibernate内部为二级缓存的扩展做了很多的实现.我们只需要实现RegionFactoryTem ...

  8. java 语言 写字板_一个简单的java语言写字板.docx

    一个简单的java语言写字板.docx 一个简单的JAVA语言写字板一.需求分析1.需求分析:现在网络上各种文档编辑器数不胜数.功能也是应有尽有,有能改变字体的,有可以改变字体颜色的,但是,这些软件有 ...

  9. 一个简单的解决方法:word文档打不开,错误提示mso.dll模块错误。

    一个简单的解决方法:word文档打不开,错误提示mso.dll模块错误. 参考文章: (1)一个简单的解决方法:word文档打不开,错误提示mso.dll模块错误. (2)https://www.cn ...

最新文章

  1. 东芝3005您的机器需要保养_两联供之东芝中央空调天氟地水详细讲解
  2. 分享Kali Linux 2016.2第43周镜像
  3. layui 键盘选中行
  4. 2021年12届蓝桥杯C++B组省赛
  5. yum之如何手动创建本地yum仓库
  6. 10亿用户之后,为什么是百度率先打破花园围墙?
  7. 获取图片中感兴趣区域的信息(Matlab实现)
  8. python旅游推荐系统_如何用Python搭建一个简单的推荐系统?
  9. mysql 关联索引_mysql中关于关联索引的问题——对a,b,c三个字段建立联合索引,那么查询时使用其中的2个作为查询条件,是否还会走索引?...
  10. atm取款机的简单程序代码_LeNet:一个简单的卷积神经网络PyTorch实现
  11. KEIL识别不出野火STM32仿真器问题解决
  12. 皮皮胡位置设定服务器,逆水寒买橘子给皮皮寒任务完成方法
  13. 数据分析:数据处理篇1
  14. t460p和t470p对比评测_老模具小升级 ThinkPad T470p商务本评测
  15. 神舟笔记本电脑降低声音
  16. Php一键转存微信文章,python如何导出微信公众号文章
  17. 如何让C语言黑窗口背景或者字体换个颜色呢?(背景和前景)
  18. 思科交换机:基本命令(上)
  19. qt抽屉菜单_Python PyQt4实现QQ抽屉效果
  20. 有香有臭个性十足“奶酪之国”种类高达345种

热门文章

  1. 程序员大部分时间都在“熟悉系统”
  2. 走在“辞职”路上的数据科学家们!
  3. 让软件自己写软件,英特尔的机器编程会取代程序员吗?
  4. 原来 8 张图,就可以搞懂「零拷贝」了!
  5. 深度讲解 Python 四大常用绘图库的“绘图原理”
  6. 京东:网传通过 Bug 抢茅台是假消息;罗永浩回应带货价格非「全网最低」;Rust 文档团队解散 | 极客头条...
  7. 看过无数 Java GC 文章,这 5 个问题你也未必知道!
  8. 雷军说的 WiFi 6 到底是什么?
  9. 一行 Python 代码能干什么?有意思!
  10. 为什么说阿里巴巴已进化成为一家世界级的科技公司?