• GuavaCache本地缓存(LoadingCache)的使用分析


    添加mavne依赖

    
        com.google.guava
        guava
        29.0-jre
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试代码及注释

    package com.swkj.customer.restapi.test;
    
    import com.google.common.cache.CacheBuilder;
    import com.google.common.cache.CacheLoader;
    import com.google.common.cache.LoadingCache;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @Description:
     * @Author: GE LIANG
     * @Date: 2022/8/26 9:33
     */
    public class CacheTest {
        private static LoadingCache loadingCache = CacheBuilder.newBuilder()
                // 并发级别
                .concurrencyLevel(8)
                // 初始容量
                .initialCapacity(10)
                // 超出阈值之后使用LRU算法溢出缓存项,只会在写入操作时候同步移除
                .maximumSize(100)
                // 缓存项自动定时刷新-》缓存项只有在被检索时才会真正刷新,即只有刷新间隔时间到了你再去get(key)才会重新去执行Loading否则就算刷新间隔时间到了也不会执行loading操作
                .refreshAfterWrite(3, TimeUnit.MINUTES)
                .build(new CacheLoader() {
                    @Override
                    public String load(String key) throws Exception {
                        /**
                         * 不同缓存数据要使用不同loadingCache获取
                         */
    
                        /**
                         * 方式1-单个插入缓存
                         */
                        // 回源操作(当通过get(key)的方式不存在的时候出发)
                        String result = "需要缓存的单条数据(可以是任何类型)";
                        return result;
    
                        /**
                         * 方式2-批量插入缓存
                         */
    //                    Map batchCacheMap = new HashMap<>();
    //                    batchCacheMap.put("key1", "abc123");
    //                    batchCacheMap.put("key2", "模拟数据-需要获取的时候使用loadingCache.get(\"key2\")即可");
    //                    loadingCache.putAll(batchCacheMap);
    //                    return batchCacheMap.get(key);
                    }
                });
    
        public static void main(String[] args) throws ExecutionException {
            /**
             * 方式一的获取方式
             */
            loadingCache.get("resultKey");
    
            /**
             * 方式二的获取方式
             */
    //        loadingCache.get("key1");
    //        loadingCache.get("key2");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    GuavaCache为开发人员提供了三种缓存被动更新机制,如下所示:

    • expireAfterAccess:缓存项在单位时间内未发生过读/写操作即被回收;
    • expireAfterWrite:缓存项在单位时间内未被更新即被回收;
    • refreshAfterWrite:缓存项离上一次更新操作多久之后会被更新;

    expireAfterWrite机制:当缓存项过期触发回源操作时,GuavaCache会通过重入锁ReentrantLock严格地控制单机只能有一个线程在执行操作,而其他线程则必须阻塞等待直至回源操作完成,不过当回源操作结束后,之前那些被阻塞的线程仍然会逐一获取锁来验证回源结果;也就是说,每个线程必须轮流地经历取锁、取值,以及释放锁的过程,这样会存在一定程度上的性能损耗,适用缓存数据强一致性的场景

    refreshAfterWrite机制:可以有效避免expireAfterWrite 机制在并发环境下因为锁资源竞争所带来的性能损耗,同expireAfterWrite类似,在执行回源操作时,单机仍然只允许一个线程在执行操作,但其他线程并不会阻塞,而是直接返回旧值;这么做虽然可以提升性能,但却仍然存在一个明显的问题,那就是refreshAfterWrite机制并不能够严格地确保返回值都是新值,适用缓存数据可以容忍短暂时间不一致场景

    当然具体应该使用哪一种缓存被动更新机制,则还需要结合具体的业务场景而定。

  • 相关阅读:
    百题千解计划【CSDN每日一练】环形单向链表。给一个单向链表,若其中包含环,请完善EntryNodeOfLoop方法..| 附多种解决方式:Python、JavaScript、Java、Go、C#..
    lazarus:数据集快速导出为excel、csv、sql及其他多种格式
    Unity 3D 2022.1 AND UnityHub 3.2 Patch
    C语言 总结const的用法
    账号安全基本措施2
    【电源专题】非隔离式开关稳压器电感布局指南
    Day83:服务攻防-开发组件安全&Jackson&FastJson各版本&XStream&CVE环境复现
    基于对立非洲秃鹫优化算法求解单目标优化问题(OAVOA)含Matlab代码
    Loss损失函数
    TASK03|概率论
  • 原文地址:https://blog.csdn.net/qq_36871369/article/details/126544012