快速搭建网站教程,正规网站建设多少费用,win7建设网站教程,wordpress切换主题后文章目录 缓存工具Cache接口LoadingCache接口CacheBuilder类CacheLoader类CacheStats类RemovalListener类 缓存工具
Guava提供了Cache接口和相关的类来支持缓存功能#xff0c;它提供了高性能、线程安全的内存缓存#xff0c;可以用于优化应用程序的性能。
特点#xff1a… 文章目录 缓存工具Cache接口LoadingCache接口CacheBuilder类CacheLoader类CacheStats类RemovalListener类 缓存工具
Guava提供了Cache接口和相关的类来支持缓存功能它提供了高性能、线程安全的内存缓存可以用于优化应用程序的性能。
特点
自动回收过期数据支持缓存项的定时回收支持缓存项的最大数量限制支持缓存项的大小限制支持缓存项的权重限制简化开发者实现基于容量的限制提供了统计信息
相关接口类
接口/类描述CacheK, V接口表示一种能够存储键值对的缓存结构LoadingCacheK, V是 Cache 接口的子接口用于在缓存中自动加载缓存项CacheLoaderK, V在使用 LoadingCache 时提供加载缓存项的逻辑CacheBuilder用于创建 Cache 和 LoadingCache 实例的构建器类CacheStats用于表示缓存的统计信息如命中次数、命中率、加载次数、存储次数等RemovalListenerK, V用于监听缓存条目被移除的事件并在条目被移除时执行相应的操作
使用示例 public static void main(String[] args) throws Exception {// 创建Cache实例LoadingCacheString, String cache CacheBuilder.newBuilder().initialCapacity(2) // 设置初始容量.concurrencyLevel(4) // 设置并发级别.maximumSize(5) // 设置最大容量
// .maximumWeight(1000) // 设置最大权重
// .weigher((WeigherString, String) (k, v) - v.length()) // 设置权重计算器.expireAfterWrite(Duration.ofSeconds(3)) // 写入后3秒过期.expireAfterAccess(Duration.ofSeconds(20)) // 访问后20秒过期.refreshAfterWrite(Duration.ofSeconds(10)) // 写入后自动刷新3秒刷新一次.recordStats() // 开启统计信息记录.removalListener(notification - { // 设置移除监听// 缓存Key被移除时触发String cause ;if (RemovalCause.EXPLICIT.equals(notification.getCause())) {cause 被显式移除;} else if (RemovalCause.REPLACED.equals(notification.getCause())) {cause 被替换;} else if (RemovalCause.EXPIRED.equals(notification.getCause())) {cause 被过期移除;} else if (RemovalCause.SIZE.equals(notification.getCause())) {cause 被缓存条数超上限移除;} else if (RemovalCause.COLLECTED.equals(notification.getCause())) {cause 被垃圾回收移除;}System.out.println(DateUtil.formatDateTime(new Date()) Key: notification.getKey() 移除了, 移除原因: cause);}).build(new CacheLoaderString, String() { // 设置缓存重新加载逻辑Overridepublic String load(String key) {// 重新加载指定Key的值String newValue value (int)Math.random()*100;System.out.println(DateUtil.formatDateTime(new Date()) Key: key 重新加载新value newValue);return newValue;}});// 将数据放入缓存cache.put(key0, value0);cache.invalidate(key0);cache.put(key1, value1);cache.put(key1, value11);cache.put(key2, value22);cache.put(key3, value3);cache.put(key4, value4);cache.put(key5, value5);cache.put(key6, value6);cache.put(key7, value7);cache.put(key8, value8);while (true) {// 获取数据System.out.println(DateUtil.formatDateTime(new Date()) get key1 value: cache.get(key1));// 统计信息System.out.println(DateUtil.formatDateTime(new Date()) get stats: cache.stats());Thread.sleep(1000);}}打印日志
2023-11-24 15:48:17 Key: key0 移除了, 移除原因: 被显式移除
2023-11-24 15:48:17 Key: key1 移除了, 移除原因: 被替换
2023-11-24 15:48:17 Key: key1 移除了, 移除原因: 被缓存条数超上限移除
2023-11-24 15:48:17 Key: key2 移除了, 移除原因: 被缓存条数超上限移除
2023-11-24 15:48:17 Key: key3 移除了, 移除原因: 被缓存条数超上限移除
2023-11-24 15:48:17 Key: key1 重新加载新valuevalue0
2023-11-24 15:48:17 Key: key4 移除了, 移除原因: 被缓存条数超上限移除
2023-11-24 15:48:17 get key1 value: value0
2023-11-24 15:48:17 get stats: CacheStats{hitCount0, missCount1, loadSuccessCount1, loadExceptionCount0, totalLoadTime3083100, evictionCount4}
2023-11-24 15:48:18 get key1 value: value0
2023-11-24 15:48:18 get stats: CacheStats{hitCount1, missCount1, loadSuccessCount1, loadExceptionCount0, totalLoadTime3083100, evictionCount4}
2023-11-24 15:48:19 get key1 value: value0
2023-11-24 15:48:19 get stats: CacheStats{hitCount2, missCount1, loadSuccessCount1, loadExceptionCount0, totalLoadTime3083100, evictionCount4}
2023-11-24 15:48:20 Key: key5 移除了, 移除原因: 被过期移除
2023-11-24 15:48:20 Key: key6 移除了, 移除原因: 被过期移除
2023-11-24 15:48:20 Key: key7 移除了, 移除原因: 被过期移除
2023-11-24 15:48:20 Key: key8 移除了, 移除原因: 被过期移除
2023-11-24 15:48:20 Key: key1 移除了, 移除原因: 被过期移除
2023-11-24 15:48:20 Key: key1 重新加载新valuevalue0
2023-11-24 15:48:20 get key1 value: value0
2023-11-24 15:48:20 get stats: CacheStats{hitCount2, missCount2, loadSuccessCount2, loadExceptionCount0, totalLoadTime3154100, evictionCount9}
2023-11-24 15:48:21 get key1 value: value0
2023-11-24 15:48:21 get stats: CacheStats{hitCount3, missCount2, loadSuccessCount2, loadExceptionCount0, totalLoadTime3154100, evictionCount9}
2023-11-24 15:48:22 get key1 value: value0
2023-11-24 15:48:22 get stats: CacheStats{hitCount4, missCount2, loadSuccessCount2, loadExceptionCount0, totalLoadTime3154100, evictionCount9}
2023-11-24 15:48:23 Key: key1 移除了, 移除原因: 被过期移除
2023-11-24 15:48:23 Key: key1 重新加载新valuevalue0
2023-11-24 15:48:23 get key1 value: value0
2023-11-24 15:48:23 get stats: CacheStats{hitCount4, missCount3, loadSuccessCount3, loadExceptionCount0, totalLoadTime3208400, evictionCount10}
2023-11-24 15:48:24 get key1 value: value0
2023-11-24 15:48:24 get stats: CacheStats{hitCount5, missCount3, loadSuccessCount3, loadExceptionCount0, totalLoadTime3208400, evictionCount10}
2023-11-24 15:48:25 get key1 value: value0
2023-11-24 15:48:25 get stats: CacheStats{hitCount6, missCount3, loadSuccessCount3, loadExceptionCount0, totalLoadTime3208400, evictionCount10}
......Cache接口
Cache接口是Guava缓存的核心接口定义了缓存的基本操作。
它是使用 CacheBuilder 创建的。它提供了基本的缓存操作如 put、get、delete等方法。同时Cache 还提供了诸如统计信息、缓存项的值获取方式、缓存项的失效、缓存项的回收等方法可以满足大多数应用的需求。
主要方法
方法描述V get(K key, Callable? extends V valueLoader)根据键获取对应的缓存值如果缓存中不存在该键会使用 valueLoader 加载并存储该值。V getIfPresent(K key)根据键获取对应的缓存值如果不存在则返回 null。MapK, V getAllPresent(Iterable? keys)获取多个键对应的缓存值的映射如果缓存中不存在某个键则该键不会出现在返回的映射中。void put(K key, V value)将键值对放入缓存中。如果键已经存在则会替换对应的值。void putAll(Map? extends K, ? extends V map)将多个键值对添加到缓存中。void invalidate(Object key)根据键从缓存中移除条目。void invalidateAll(Iterable? keys)根据键集合移除多个条目。void invalidateAll()移除缓存中的所有条目。long size()返回缓存中的条目数。CacheStats stats()返回缓存的统计信息。ConcurrentMapK, V asMap()返回缓存的并发映射视图。void cleanUp()执行缓存的清理操作。
LoadingCache接口
LoadingCache 继承自 Cache 接口它是一个带有自动加载功能的缓存接口。
在使用 LoadingCache 时如果缓存中不存在所需的键值对则会自动调用CacheLoader的加载方法进行加载并将加载的结果存入缓存中。
主要方法
方法说明get(K key)根据指定的键检索值如果键不存在将调用 CacheLoader 进行加载并返回对应的值getAll(Iterable? extends K keys)根据给定的键集合批量检索值并返回一个 Map 对象对于已缓存的键将直接返回对应的值对于未缓存的键将通过 CacheLoader 进行加载。getUnchecked(K key)获取指定键对应的值如果缓存中不存在该键则返回 null不会触发CacheLoader 加载。refresh(K key)刷新指定键对应的值即使用 CacheLoader 重新加载该键对应的值并更新缓存。
CacheBuilder类
CacheBuilder类是用于创建Guava缓存的构建器。可以使用该类的newBuilder()方法创建一个构建器实例并通过一系列方法设置缓存的属性例如最大容量、过期时间等。最后可以通过build()方法构建一个Cache实例。
主要方法
方法说明newBuilder()创建一个新的 CacheBuilder 实例from(CacheBuilderSpec spec)根据给定的规范字符串创建一个 CacheBuilder 实例from(String spec)根据给定的规范字符串创建一个 CacheBuilder 实例initialCapacity(int initialCapacity)设置缓存的初始容量concurrencyLevel(int concurrencyLevel)设置并发级别用于估计同时写入的线程数maximumSize(long maximumSize)设置缓存的最大容量maximumWeight(long maximumWeight)设置缓存的最大权重weigher(Weigher? super K1, ? super V1 weigher)设置缓存的权重计算器weakKeys()使用弱引用存储缓存键例如键的引用没有被其他对象引用时可以被垃圾回收weakValues()使用弱引用存储缓存值例如值的引用没有被其他对象引用时可以被垃圾回收softValues()使用软引用存储缓存值例如当内存不足时可以被垃圾回收expireAfterWrite(java.time.Duration duration)设置写入后过期时间expireAfterWrite(long duration, TimeUnit unit)设置写入后过期时间expireAfterAccess(java.time.Duration duration)设置访问后过期时间expireAfterAccess(long duration, TimeUnit unit)设置访问后过期时间refreshAfterWrite(java.time.Duration duration)设置写入后自动刷新时间refreshAfterWrite(long duration, TimeUnit unit)设置写入后自动刷新时间ticker(Ticker ticker)设置用于衡量缓存时间的时钟源removalListener(RemovalListener? super K1, ? super V1 listener)设置缓存条目移除监听器recordStats()开启缓存统计信息记录build(CacheLoader? super K1, V1 loader)使用指定的 CacheLoader 构建缓存build()构建缓存如果没有指定 CacheLoader则需要使用 get 方法手动加载缓存项
部分方法详解 initialCapacity设置缓存的初始容量 这个方法将通过一个整数值设置缓存的初始大小。它是一个可选的方法如果没有指定缓存将采用默认的初始容量。 concurrencyLevel设置并发级别 用于估计同时写入的线程数。这个方法将通过一个整数值设置并发级别用于内部数据结构的调整以提高并发写入的性能。它是一个可选的方法缺省值为 4。 maximumSize设置缓存的最大容量 这个方法将通过一个 long 类型的值设置缓存的最大容量。当缓存的条目数达到这个容量时会触发缓存清除策略来移除一些条目以腾出空间。它是一个可选的方法如果没有指定最大容量缓存将不会有大小限制。 maximumWeight设置缓存的最大权重 这个方法将通过一个 long 类型的值设置缓存的最大权重。权重可以根据缓存条目的大小计算通常用于缓存对象大小不同的场景。当缓存的总权重达到这个值时会触发缓存清除策略来移除一些条目以腾出空间。它是一个可选的方法如果没有指定最大权重缓存将不会有权重限制。 weigher设置缓存的权重计算器 这个方法将通过一个实现了 Weigher 接口的对象设置缓存的权重计算器。通过权重计算器可以根据缓存条目的键和值来计算它们的权重以便在达到最大权重时触发缓存清除策略。它是一个可选的方法如果没有设置权重计算器缓存将不会有权重限制。 expireAfterWrite设置写入后过期时间 这个方法通过一个 java.time.Duration 对象设置缓存条目的写入后过期时间。过期时间从最后一次写入条目开始计算。一旦超过指定的时间条目将被认为是过期的并被清除。这是一个可选的方法如果没有指定过期时间条目将不会主动过期。 expireAfterAccess设置访问后过期时间 这个方法通过一个 java.time.Duration 对象设置缓存条目的访问后过期时间。过期时间从最后一次访问条目开始计算。一旦超过指定的时间条目将被认为是过期的并被清除。这是一个可选的方法如果没有指定过期时间条目将不会主动过期。 refreshAfterWrite设置写入后自动刷新时间 这个方法通过一个 java.time.Duration 对象设置缓存条目的自动刷新时间。自动刷新时间从最后一次写入条目开始计算。一旦超过指定的时间当条目被访问时缓存将自动刷新该条目即会调用 CacheLoader 的 load 方法重新加载该条目。这是一个可选的方法如果没有设置自动刷新时间条目将不会自动刷新。 recordStats()开启缓存统计信息记录 这个方法用于开启缓存的统计信息记录功能。一旦开启可以通过 Cache.stats() 方法获取缓存的统计信息如命中率、加载次数、平均加载时间等。这是一个可选的方法如果不开启统计信息记录将无法获取缓存的统计信息。
注意事项 maximumSize与maximumWeight不能同时设置 设置maximumWeight时必须设置weigher 当缓存失效后refreshAfterWrite设置的写入后自动刷新时间不会再有用 注意expireAfterWrite、expireAfterAccess、refreshAfterWrite三个值的使用 开启recordStats后才进行统计
CacheLoader类
CacheLoader 可以被视为一种从存储系统如磁盘、数据库或远程节点中加载数据的方法。
CacheLoader 通常搭配refreshAfterWrite使用在写入指定的时间周期后会调用CacheLoader 的load方法来获取并刷新为新值。
load 方法在以下情况下会被触发调用 当设置了refreshAfterWrite写入后自动刷新时间达到自动刷新时间时会调用 load 方法来重新加载该键的值。 调用 Cache.get(key) 方法获取缓存中指定键的值时如果该键的值不存在则会调用 load 方法来加载该键的值。 调用 Cache.get(key, callable) 方法获取缓存中指定键的值时如果该键的值存在则直接返回如果该键的值不存在则会调用 callable 参数指定的回调函数来计算并加载该键的值。 调用 Cache.getUnchecked(key) 方法获取缓存中指定键的值时无论该键的值存在与否都会调用 load 方法来加载该键的值。
需要注意的是当调用 load 方法加载缓存值时可能会发生 IO 操作或其他耗时操作因此建议在加载操作中使用异步方式来避免阻塞主线程。另外加载操作的实现要考虑缓存的一致性和并发性避免多个线程同时加载同一个键的值。
CacheStats类
CacheStats 对象提供了诸如缓存命中率、加载缓存项数、缓存项回收数等统计信息的访问。
它可以通过 Cache.stats() 方法来获取从而方便开发者监控缓存状态。
主要属性
属性描述hitCount缓存命中次数。表示从缓存中成功获取数据的次数missCount缓存未命中次数。表示从缓存中未能获取到数据的次数loadSuccessCount加载数据成功次数。表示通过 CacheLoader 成功加载数据的次数loadExceptionCount加载数据异常次数。表示通过 CacheLoader 加载数据时发生异常的次数totalLoadTime加载数据总耗时。表示通过 CacheLoader 加载数据的总时间evictionCount缓存项被移除的次数只记录因空超过设置的最大容量而进行缓存项移除的次数
RemovalListener类
RemovalListener 用于在缓存中某个值被移除时执行相应的回调操作。
可以使用 CacheBuilder.removalListener() 方法为缓存设置 RemovalListener。
RemovalListener 的使用 创建一个实现 RemovalListener 接口的类实现 onRemoval 方法。这个方法会在缓存项被移除时被调用接受两个参数: key 和 value。key 是被移除的缓存项的键value 是被移除的缓存项的值。你可以根据需要在 onRemoval 方法中实现自定义的逻辑。 使用 CacheBuilder 的 removalListener 方法将创建的 RemovalListener 对象传递给它。 缓存项被移除时onRemoval 方法会自动被调用方法会传入一个RemovalNotification 类型的参数里面包含相应的 key 和 value等信息。你可以在这个方法中执行自定义的业务逻辑例如日志记录、资源清理等操作。 RemovalNotification RemovalNotification 是 Guava 中用于表示缓存项被移除的通知的类。当在 Guava Cache 中注册了 RemovalListener 后RemovalNotification 对象会在缓存项被移除时传递给 RemovalListener 的 onRemoval 方法。 RemovalNotification 包含了有关被移除缓存项的一些重要信息例如键、值以及移除原因。下面是 RemovalNotification 类中常用的属性和方法 getKey()获取被移除的缓存项的键。 getValue()获取被移除的缓存项的值。 getCause()获取移除原因它是一个枚举类型RemovalCause表示缓存项被移除的原因。 RemovalCause的可选值 EXPLICIT条目被显式删除例如通过调用 Cache.invalidate(key) 方法。REPLACED条目被替换例如通过调用 Cache.put(key, value) 方法重复放入相同的键。EXPIRED缓存条目由于达到了指定的过期时间而被移除。SIZE缓存条目由于超过了指定的大小限制而被移除。COLLECTED缓存条目被垃圾回收移除。这是在启用了缓存值的弱引用或软引用时发生的。 使用 RemovalNotification 可以让你在缓存项被移除时获取相关信息并根据移除原因采取适当的处理措施。例如你可以根据移除原因记录日志、执行清理操作、发送通知等。这样能够增强缓存的功能和可观察性。
注意事项
RemovalListener 的 onRemoval 方法会在移除操作发生时同步调用因此请确保不要在此方法中做耗时的操作以免阻塞缓存的性能。如果在缓存移除过程中抛出任何异常它将被捕获并记录不会影响缓存的正常运行。需要注意的是RemovalListener 只会在通过 Cache 的操作如 invalidate、invalidateAll、put 进行替换触发移除时被调用并不会在缓存项因为过期失效而自动移除时被调用。
使用 RemovalListener 可以方便地在缓存项被移除时执行一些自定义的操作例如清理相关资源、更新其他缓存或发送通知等。根据实际需要合理利用 RemovalListener 可以增强缓存的功能和灵活性。