用Java写一个简单的缓存类

/ 并发编程 / 0 条评论 / 755浏览

前言

使用缓存已经是开发中老生常谈的一件事了,常用专门处理缓存的工具比如Redis、MemCache等,但是有些时候可能需要一些简单的缓存处理,没必要用上这种专门的缓存工具,那么自己写一个缓存类最合适不过了。

一、分析

首先分析一下缓存类该如何设计,这里我以一种非常简单的方式来实现一个缓存类,这也是我一直以来使用的设计方案。

为了明确功能,首先定义一个接口类CacheInt,然后是缓存实现的工具类CacheUtil。然后再看其中的功能,为了存取方便,缓存应是以键值对的形式存取,为了适应更多的场景,所以在存取的时候可以加一个缓存过期时间,然后再加上其他常见的添加、获取、删除、缓存大小、是否存在key、清理过期缓存等方法,整个缓存工具的方法差不多就是这些。

缓存类需要注意的问题:

  1. 缓存对象应该是唯一的,也就是单例的;
  2. 缓存的操作方法要同步,在多线程并发条件下防止出错;
  3. 缓存的容器应该具有较高的并发性能,ConcurrentHashMap是一个不错的选择。

二、具体实现

1. CacheInt接口的定义

CacheInt接口的定义如下:

2. CacheUtil的具体实现

缓存实现的核心就是CacheUtil,下面结合注释进行说明,为了避免文章篇幅冗杂,以下截图就是完整源码截图,并且保持先后顺序。

首先是类定义和其属性定义,其中本类实例对象用volatile进行修饰提高可见性,初始化缓存容量用于初始化ConcurrentHashMap缓存容器的大小,此大小根据实际应用场景进行优化

然后是内部类Entry的定义,该类是用来存储实际数据的,为了方便处理过期时间,添加初始化时间戳、过期时间等属性。

然后是使用双检锁单例方式获取本类实例对象,因为单例只能存在唯一的特点,所以注意构造函数需要设为private

接下来是存入缓存数据put()方法,这里的clearExpiredCache()是清理过期缓存,后面会看到方法体,因为在我项目中存入缓存的情况较少,所以这里我固定了每次存之前先清理一次过期时间缓存,这里可以根据自己项目实际情况进行优化。

然后是获取缓存get()方法,因为获取数据的时间较为多数,所以这里我设定了三分之一的概率清理过期缓存,适当地释放堆内存,并且在获取时检测是否过期,如果已过期然而还获取到了,就删除并返回空。

然后就是比较常规的一些方法,具体可以看代码

最后一个方法就是清理过期缓存,这里你可以选择启动一个监听线程实时地清理缓存,也可以选择在适当时机进行一次清理,比如我这里就是在存在put和get操作时固定或概率地清理缓存。

三、并发测试

普通的实现测试这里就不展示了,肯定是没问题的,读者简单写一些测试样例即可,这里主要展示一下并发测试,因为在实际情况中存在并发处理缓存情况,为了确保其正确性,所以并发测试是必须要做的,下面放出我的测试样例。

最后测试的表现是很好,没有出现不正确的情况,部分测试结果截图如下:

四、拓展

该类只是简单的实现了缓存的过程,但是在实际应用中不见得能很好地表现,首先它的容量肯定有限,不能存太多缓存,因为使用的是JVM堆内的内存,其次其功能也较为简单,比如不支持LRU淘汰等,这个可以用双链表+Map或者是LinkedHashMap去实现,更多功能都可以拓展。

微信公众号浏览体验更佳,在这里还有更多优秀文章为你奉上,快来关注吧!

北风IT之路