• 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机制并不能够严格地确保返回值都是新值,适用缓存数据可以容忍短暂时间不一致场景

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

  • 相关阅读:
    【图像分割】基于和声搜索算法实现图像多级阈值分割附matlab代码
    《HelloGitHub》第 79 期
    虚拟dom及diff算法之 —— snabbdom
    有哪些比较流行的 C、C++和Java 的入门级项目?
    MySQL 读写分离配置实践
    NativeBuferring,一种零分配的数据类型[下篇]
    Oracle 手工建库
    [渲染层错误] [jsbridge] invoke remoteDebugInfo fail: too eayly.
    【深度学习实验】循环神经网络(三):门控制——自定义循环神经网络LSTM(长短期记忆网络)模型
    63 x的平方根
  • 原文地址:https://blog.csdn.net/qq_36871369/article/details/126544012