概述

来源

Hutool-cache模块最早受到jodd-cache的启发(如今大部分逻辑依旧与jodd保持一致),此模块提供一种缓存的简单实现方案,在小型项目中对于简单的缓存需求非常好用。

介绍

Hutoo-cache模块提供了几种缓存策略实现:

FIFOCache

FIFO(first in first out) 先进先出策略。元素不停的加入缓存直到缓存满为止,当缓存满时,清理过期缓存对象,清理后依旧满则删除先入的缓存(链表首部对象)。
优点:简单快速 缺点:不灵活,不能保证最常用的对象总是被保留

LFUCache

LFU(least frequently used) 最少使用率策略。根据使用次数来判定对象是否被持续缓存(使用率是通过访问次数计算),当缓存满时清理过期对象,清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,以便新对象进入后可以公平计数。

LRUCache

LRU (least recently used)最近最久未使用缓存。根据使用时间来判定对象是否被持续缓存,当对象被访问时放入缓存,当缓存满了,最久未被使用的对象将被移除。此缓存基于LinkedHashMap,因此当被缓存的对象每被访问一次,这个对象的key就到链表头部。这个算法简单并且非常快,他比FIFO有一个显著优势是经常使用的对象不太可能被移除缓存。缺点是当缓存满时,不能被很快的访问。

TimedCache

定时缓存,对被缓存的对象定义一个过期时间,当对象超过过期时间会被清理。此缓存没有容量限制,对象只有在过期后才会被移除

WeakCache

弱引用缓存。对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除。该类使用了WeakHashMap做为其实现,缓存的清理依赖于JVM的垃圾回收。


FileCach

FileCach是一个独立的缓存,主要是将小文件以byte[]的形式缓存到内容中,减少文件的访问,以解决频繁读取文件引起的性能问题。
主要实现有:

概述

CacheUtil是缓存创建的快捷工具类。用于快速创建不同的缓存对象。

使用

  1. //新建FIFOCache
  2. Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);

同样其它类型的Cache也可以调用newXXX的方法创建。

先入先出-FIFOCache

介绍

FIFO(first in first out) 先进先出策略。元素不停的加入缓存直到缓存满为止,当缓存满时,清理过期缓存对象,清理后依旧满则删除先入的缓存(链表首部对象)。
优点:简单快速 缺点:不灵活,不能保证最常用的对象总是被保留

使用

  1. Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
  2. //加入元素,每个元素可以设置其过期时长,DateUnit.SECOND.getMillis()代表每秒对应的毫秒数,在此为3秒
  3. fifoCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
  4. fifoCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
  5. fifoCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
  6. //由于缓存容量只有3,当加入第四个元素的时候,根据FIFO规则,最先放入的对象将被移除
  7. fifoCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
  8. //value1为null
  9. String value1 = fifoCache.get("key1");

最少使用-LFUCache

介绍

LFU(least frequently used) 最少使用率策略。根据使用次数来判定对象是否被持续缓存(使用率是通过访问次数计算),当缓存满时清理过期对象,清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,以便新对象进入后可以公平计数。

使用

  1. Cache<String, String> lfuCache = CacheUtil.newLFUCache(3);
  2. //通过实例化对象创建
  3. //LFUCache<String, String> lfuCache = new LFUCache<String, String>(3);
  4. lfuCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
  5. lfuCache.get("key1");//使用次数+1
  6. lfuCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
  7. lfuCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
  8. lfuCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
  9. //由于缓存容量只有3,当加入第四个元素的时候,根据LRU规则,最少使用的将被移除(2,3被移除)
  10. String value2 = lfuCache.get("key2");//null
  11. String value3 = lfuCache.get("key3");//null

最近最久未使用-LRUCache

介绍

LRU (least recently used)最近最久未使用缓存。根据使用时间来判定对象是否被持续缓存,当对象被访问时放入缓存,当缓存满了,最久未被使用的对象将被移除。此缓存基于LinkedHashMap,因此当被缓存的对象每被访问一次,这个对象的key就到链表头部。这个算法简单并且非常快,他比FIFO有一个显著优势是经常使用的对象不太可能被移除缓存。缺点是当缓存满时,不能被很快的访问。

使用

  1. Cache<String, String> lruCache = CacheUtil.newLRUCache(3);
  2. //通过实例化对象创建
  3. //LRUCache<String, String> lruCache = new LRUCache<String, String>(3);
  4. lruCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
  5. lruCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
  6. lruCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
  7. lruCache.get("key1");//使用时间推近
  8. lruCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
  9. //由于缓存容量只有3,当加入第四个元素的时候,根据LRU规则,最少使用的将被移除(2被移除)
  10. String value2 = lruCache.get("key");//null

超时-TimedCache

介绍

定时缓存,对被缓存的对象定义一个过期时间,当对象超过过期时间会被清理。此缓存没有容量限制,对象只有在过期后才会被移除。

使用

  1. //创建缓存,默认4毫秒过期
  2. TimedCache<String, String> timedCache = CacheUtil.newTimedCache(4);
  3. //实例化创建
  4. //TimedCache<String, String> timedCache = new TimedCache<String, String>(4);
  5. timedCache.put("key1", "value1", 1);//1毫秒过期
  6. timedCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 5);
  7. timedCache.put("key3", "value3");//默认过期(4毫秒)
  8. //启动定时任务,每5毫秒秒检查一次过期
  9. timedCache.schedulePrune(5);
  10. //等待5毫秒
  11. ThreadUtil.sleep(5);
  12. //5毫秒后由于value2设置了5毫秒过期,因此只有value2被保留下来
  13. String value1 = timedCache.get("key1");//null
  14. String value2 = timedCache.get("key2");//value2
  15. //5毫秒后,由于设置了默认过期,key3只被保留4毫秒,因此为null
  16. String value3 = timedCache.get("key3");//null
  17. //取消定时清理
  18. timedCache.cancelPruneSchedule();Copy to clipboardErrorCopied

如果用户在超时前调用了get(key)方法,会重头计算起始时间。举个例子,用户设置key1的超时时间5s,用户在4s的时候调用了get("key1"),此时超时时间重新计算,再过4s调用get("key1")方法值依旧存在。如果想避开这个机制,请调用get("key1", false)方法。

说明 如果启动了定时器,那会定时清理缓存中的过期值,但是如果不起动,那只有在get这个值得时候才检查过期并清理。不起动定时器带来的问题是:有些值如果长时间不访问,会占用缓存的空间。

弱引用-WeakCache

介绍

弱引用缓存。对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除。该类使用了WeakHashMap做为其实现,缓存的清理依赖于JVM的垃圾回收。

使用

与TimedCache使用方法一致:

  1. WeakCache<String, String> weakCache = CacheUtil.newWeakCache(DateUnit.SECOND.getMillis() * 3);

WeakCache也可以像TimedCache一样设置定时清理时间,同时具备垃圾回收清理。

文件缓存-FileCache

介绍

FileCache主要是将小文件以byte[]的形式缓存到内存中,减少文件的访问,以解决频繁读取文件引起的性能问题。

实现

  • LFUFileCache
  • LRUFileCache

    使用

    1. //参数1:容量,能容纳的byte数
    2. //参数2:最大文件大小,byte数,决定能缓存至少多少文件,大于这个值不被缓存直接读取
    3. //参数3:超时。毫秒
    4. LFUFileCache cache = new LFUFileCache(1000, 500, 2000);
    5. byte[] bytes = cache.getFileBytes("d:/a.jpg");
    LRUFileCache的使用与LFUFileCache一致,不再举例。