天天看点

Java开发者的福音 - Hutool工具(缓存组件)

作者:AI搬运工秉尘

简介

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类源码:

Java开发者的福音 - Hutool工具(缓存组件)

从源码中可以看出,CacheUtil类为FIFOCache,LFUCache,LRUCache三类缓存分别提供了两种实现,这三种缓存本身支持对缓存容量和缓存时间的设定。

Java开发者的福音 - Hutool工具(缓存组件)

先进先出策略-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);           

源码实现:

Java开发者的福音 - Hutool工具(缓存组件)

从源码上可以看出,FIFOCache底层实现是LinkedHashMap。

Java开发者的福音 - Hutool工具(缓存组件)

最少使用策略-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);                    

源码实现:

Java开发者的福音 - Hutool工具(缓存组件)

从源码上可以看出,LFUCache底层实现是HashMap。

Java开发者的福音 - Hutool工具(缓存组件)

最近使用策略-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);
           

源码实现:

Java开发者的福音 - Hutool工具(缓存组件)

从源码可以看出,LRUCache底层实现是FixedLinkedHashMap。

Java开发者的福音 - Hutool工具(缓存组件)

超时策略-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这个值得时候才检查过期并清理。不起动定时器带来的问题是:有些值如果长时间不访问,会占用缓存的空间。

源码实现:

Java开发者的福音 - Hutool工具(缓存组件)

通过源码可以看出,TimedCache的底层实现是HashMap。

Java开发者的福音 - Hutool工具(缓存组件)

弱引用策略-WeakCache

对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。

该类使用了WeakHashMap做为其实现,缓存的清理依赖于JVM的垃圾回收。

用法与TimedCache相同。

Java开发者的福音 - Hutool工具(缓存组件)

文件缓存策略-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");           

源码实现:

Java开发者的福音 - Hutool工具(缓存组件)

从源码可以看出LFUFileCache提供了三种构造方法,开发人员可根据自己的需求选择。

Java开发者的福音 - Hutool工具(缓存组件)

Hutool中提供的缓存实现就是这些了,你学会了吗?

#挑战30天在头条写日记#