网站首页 > java教程 正文
简介
Hutool-cache模块目前提供了六种缓存策略实现:
- FIFOCache,FIFO(first in first out) 先进先出策略。
- LFUCache,LFU(least frequently used) 最少使用率策略。
- LRUCache,LRU (least recently used) 最近使用策略。
- TimedCache,定时缓存策略。
- WeakCache,弱引用缓存策略。
- FileCache,小文件缓存策略。
缓存创建工具类-CacheUtil
可以通过CacheUtil工具类创建不同类型的缓存对象。
代码示例:
Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
CacheUtil类源码:
从源码中可以看出,CacheUtil类为FIFOCache,LFUCache,LRUCache三类缓存分别提供了两种实现,这三种缓存本身支持对缓存容量和缓存时间的设定。
先进先出策略-FIFOCache
元素不停的加入缓存直到缓存满为止,当缓存满时,清理过期缓存对象,清理后依旧满则删除先入的缓存(链表首部对象)。
优点:简单快速
缺点:不灵活,不能保证最常用的对象总是被保留。
代码示例:
// 定义一个缓存容量为3的缓存对象
Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
// 向缓存中加入元素
fifoCache.put("key1", "value1");
fifoCache.put("key2", "value2");
fifoCache.put("key3", "value3");
// 此时缓存容量已满,加入第四个元素
fifoCache.put("key4", "value4");
// 根据FIFO规则,最先放入的对象将被移除,此时key1对应的值为null
Console.log(fifoCache.get("key1") == null);
源码实现:
从源码上可以看出,FIFOCache底层实现是LinkedHashMap。
最少使用策略-LFUCache
根据使用次数来判定对象是否被持续缓存(使用率是通过访问次数计算),当缓存满时清理过期对象,清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,以便新对象进入后可以公平计数。
代码示例:
// 定义一个缓存容量为3的缓存对象
Cache<String, String> lfuCache = CacheUtil.newLFUCache(3);
// 向缓存中加入元素
lfuCache.put("key1", "value1");
lfuCache.put("key2", "value2");
lfuCache.put("key3", "value3");
// 使用一次key1缓存
lfuCache.put("key1");
// 此时缓存容量已满,加入第四个元素
lfuCache.put("key4", "value4");
// 根据LRU规则,使用次数最少的将被移除(2,3的使用次数都是0,被移除)
Console.log(fifoCache.get("key2") == null);
Console.log(fifoCache.get("key3") == null);
源码实现:
从源码上可以看出,LFUCache底层实现是HashMap。
最近使用策略-LRUCache
根据使用时间来判定对象是否被持续缓存,当对象被访问时放入缓存,当缓存满了,最久未被使用的对象将被移除。此缓存基于LinkedHashMap,因此当被缓存的对象每被访问一次,这个对象的key就到链表头部。这个算法简单并且非常快,他比FIFO有一个显著优势是经常使用的对象不太可能被移除缓存。缺点是当缓存满时,不能被很快的访问。
代码示例:
// 定义一个缓存容量为3的缓存对象
Cache<String, String> lruCache = CacheUtil.newLRUCache(3);
// 向缓存中加入元素
lruCache.put("key1", "value1");
lruCache.put("key2", "value2");
lruCache.put("key3", "value3");
// 使用一次key1缓存
lruCache.get("key1");
// 此时缓存容量已满,加入第四个元素
lruCache.put("key4", "value4");
// 根据LRU规则,时间最久未使用的将被移除(2被移除)
Console.log(fifoCache.get("key2") == null);
源码实现:
从源码可以看出,LRUCache底层实现是FixedLinkedHashMap。
超时策略-TimedCache
对被缓存的对象定义一个过期时间,当对象超过过期时间会被清理。
此缓存没有容量限制,对象只有在过期后才会被移除。
代码示例:
// 定义一个默认过期时间为4毫秒的缓存对象,注意单位是毫秒
TimedCache<String, String> timedCache = CacheUtil.newTimedCache(4);
// 向缓存中加入元素
// 1毫秒过期
timedCache.put("key1", "value1", 1);
// 5秒过期
timedCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 5);
// 默认时间为4毫秒过期
timedCache.put("key3", "value3");
//启动定时任务,每5毫秒清理一次过期条目,注释此行首次启动仍会清理过期条目
timedCache.schedulePrune(5);
//等待5毫秒
ThreadUtil.sleep(5);
//5毫秒后由于value2设置了5毫秒过期,因此只有value2被保留下来
String value1 = timedCache.get("key1");//null
String value2 = timedCache.get("key2");//value2
//5毫秒后,由于设置了默认过期,key3只被保留4毫秒,因此为null
String value3 = timedCache.get("key3");//null
//取消定时清理
timedCache.cancelPruneSchedule();
如果用户在超时前调用了get(key)方法,会重头计算起始时间。
举个例子,用户设置key1的超时时间5s,用户在4s的时候调用了get("key1"),此时超时时间重新计算,再过4s调用get("key1")方法值依旧存在。
如果想避开这个机制,请调用get("key1", false)方法。
说明 如果启动了定时器,那会定时清理缓存中的过期值,但是如果不起动,那只有在get这个值得时候才检查过期并清理。不起动定时器带来的问题是:有些值如果长时间不访问,会占用缓存的空间。
源码实现:
通过源码可以看出,TimedCache的底层实现是HashMap。
弱引用策略-WeakCache
对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。
该类使用了WeakHashMap做为其实现,缓存的清理依赖于JVM的垃圾回收。
用法与TimedCache相同。
文件缓存策略-FileCache
主要是将小文件以byte[]的形式缓存到内存中,减少文件的访问,以解决频繁读取文件引起的性能问题。
注意:CacheUtil工具类中并没有实现对FileCache缓存的创建,FileCache本身提供了两种实现,LFUFileCache 和 LRUFileCache。
代码示例:
//参数1:容量,能容纳的byte数
//参数2:最大文件大小,byte数,决定能缓存至少多少文件,大于这个值不被缓存直接读取
//参数3:超时。毫秒
LFUFileCache cache = new LFUFileCache(1000, 500, 2000);
byte[] bytes = cache.getFileBytes("d:/a.jpg");
源码实现:
从源码可以看出LFUFileCache提供了三种构造方法,开发人员可根据自己的需求选择。
Hutool中提供的缓存实现就是这些了,你学会了吗?
- 上一篇: 一文搞懂JAVA 中的引用
- 下一篇: IDEA如何找到在IDEA中下载jdk
猜你喜欢
- 2025-01-01 一文搞懂JAVA 中的引用
- 2025-01-01 Java并发编程(20)CPU处理器中高速缓存的数据结构
- 2025-01-01 Java 缓冲输入输出是什么?怎么用?
- 2025-01-01 网站慢?试试这个Java实时缓存高招!
- 2025-01-01 追求极致性能,Java高速缓存 Caffeine
- 2025-01-01 实战派 | Java项目中玩转Redis6.0客户端缓存
- 2025-01-01 13 如何利用缓存实现万级并发扣减
- 2025-01-01 Java线程池newCachedThreadPool和newFixedThreadPool对比
- 2025-01-01 JVM简介—1.Java内存区域
- 2025-01-01 不同业务场景该如何选择缓存的读写策略?
你 发表评论:
欢迎- 04-24Java Collections 工具类集合框架中常用算法解析
- 04-24桶排序的简单理解
- 04-24Java集合框架底层实现原理大揭秘
- 04-24Java 集合框架全面解析:选对数据结构,提升开发效率
- 04-24c#集合排序
- 04-24Java面试中常被问到的集合类深度解读
- 04-24VBA技术资料MF278:对集合进行排序
- 04-24Spring 最常用的 7 大类注解,史上最强整理
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)