美文网首页
Guava-CacheLoader

Guava-CacheLoader

作者: 63f4fe6cfa47 | 来源:发表于2022-03-14 21:47 被阅读0次

    CacheBulider

    适用性

    缓存在很多场景下都是相当有用的。例如,计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存。 缓存在很多场景下都是相当有用的。例如,计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存。

    Guava Cache与ConcurrentMap很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除。相对地,Guava Cache为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管LoadingCache 不回收元素,它也是很有用的,因为它会自动加载缓存。

    通常来说,Guava Cache适用于:

    • 你愿意消耗一些内存空间来提升速度。
    • 你预料到某些键会被查询一次以上。
    • 缓存中存放的数据总量不会超出内存容量。(Guava Cache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。如果这不符合你的需求,请尝试Memcached这类工具)

    如果你的场景符合上述的每一条,Guava Cache就适合你。

    如同范例代码展示的一样,Cache实例通过CacheBuilder生成器模式获取,但是自定义你的缓存才是最有趣的部分。

    :如果你不需要Cache中的特性,使用ConcurrentHashMap有更好的内存效率——但Cache的大多数特性都很难基于旧有的ConcurrentMap复制,甚至根本不可能做到。

    1. 基础创建CacheBuilder

        public void test2() {
            // 新建CacheBuilder
            Cache<Integer, String> cache = CacheBuilder.newBuilder().build();
            cache.put(1, "a");
            cache.put(2, "b");
            // 输出: a
            System.out.println(cache.getIfPresent(1));
            // 输出: null
            System.out.println(cache.getIfPresent(3));
            // 输出: {1=a, 2=b}
            System.out.println(cache.getAllPresent(ImmutableList.of(1,2,3)));
        }
    

    2. 无缓存时,自定义缓存值

        public void test3() {
            // 遇到不存在的key,定义默认缓存值
            CacheLoader cacheLoader = new CacheLoader<Integer,String>() {
                @Override
                public String load(Integer key) throws Exception {
                    return "缓存中找不到 key[" + key + "]对应的值";
                }
            };
    
            // 1. 在cache定义时设置通用缓存模版
            LoadingCache<Integer, String> cache1 = CacheBuilder.newBuilder().build(cacheLoader);
            cache1.put(1, "a");
            // 输出: a
            System.out.println(cache1.getIfPresent(1));
            try {
                // 输出: {1=a, 2=缓存中找不到 key[2]对应的值}
                System.out.println(cache1.getAll(ImmutableList.of(1,2)));
                // 输出: 缓存中找不到 key[3]对应的值
                System.out.println(cache1.get(3));
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
    
             // 2. 在获取缓存值时设置缓存
             Cache<Integer, String> cache2 = CacheBuilder.newBuilder().build();
             cache2.put(1, "a");
            // 输出: a
             System.out.println(cache2.getIfPresent(1));
             try {
                 // 输出: key2
                 String value = cache2.get(2, () -> "key2");
                 System.out.println(value);
             } catch (ExecutionException e) {
                 e.printStackTrace();
             }
        }
    

    3. 控制缓存大小

        public void test4() {
            // 1. 基于缓存多少
            Cache<Integer, String> cache1 = CacheBuilder.newBuilder()
                    .maximumSize(2L)  // 设置缓存上限,最多两个
                    .build();
            cache1.put(1, "a");
            cache1.put(2, "b");
            cache1.put(3, "c");
            // 输出: {3=c, 2=b}
            System.out.println(cache1.asMap());
            // 输出: b
            System.out.println(cache1.getIfPresent(2));
            cache1.put(4, "d");
            // 由于key 2被调用获取过,所以key 3会被回收 输出: {2=b, 4=d}
            System.out.println(cache1.asMap());
        }
    

    4. 控制缓存回收的时间

       public void test5() {
            // 1. 设置缓存写入后多久过期
            Cache<Integer, Integer> cache1 = CacheBuilder.newBuilder()
                    // 缓存写入2s后过期
                    .expireAfterWrite(2, TimeUnit.SECONDS)
                    .build();
            cache1.put(1,1);
            // 输出: {1=1}
            System.out.println(cache1.asMap());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 输出: {}
            System.out.println(cache1.asMap());
    
            // 2. 设置缓存在给定时间内没有被读/写访问后过期
            Cache<Integer, Integer> cache2 = CacheBuilder.newBuilder()
                    // 缓存读取2s后过期
                    .expireAfterAccess(2, TimeUnit.SECONDS)
                    .build();
            cache2.put(1,1);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            cache2.getIfPresent(1);
            // 输出: {}
            System.out.println(cache2.asMap());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 输出: {}
            System.out.println(cache2.asMap());
        }
    

    5. 手动清除缓存

        public void test6() {
            // 清除缓存中的数据
            Cache<Integer, String> cache = CacheBuilder.newBuilder().build();
            cache.put(1, "a");
            System.out.println(cache.asMap());  // 输出: {1=a}
            cache.invalidateAll();  // 清除所有缓存
            System.out.println(cache.asMap());  // 输出: {}
            cache.put(2, "b");
            System.out.println(cache.asMap());  // 输出: {2=b}
            cache.invalidate(2);  // 清除指定缓存
            System.out.println(cache.asMap());  // 输出: {}
            cache.put(1, "a");
            cache.put(2, "b");
            cache.put(3, "c");
            System.out.println(cache.asMap());  // 输出: {2=b, 1=a, 3=c}
            cache.invalidateAll(ImmutableList.of(1,2));  // 批量清除缓存
            System.out.println(cache.asMap());  // 输出: {3=c}
        }
    

    6. 设置监听器

        public void test7() {
            // 设置移除监听器
            LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder()
                    .expireAfterWrite(2, TimeUnit.SECONDS)  // 设置2s后过期时间
                    .removalListener(notification -> System.out.println(
                            "移除key[" + notification.getKey()
                                    + "],value[" + notification.getValue()
                                    + "],移除原因[" + notification.getCause() + "]")
                    )  // 设置移除监听器,并设置输出模版
                    .build(
                            new CacheLoader<Integer, Integer>() {
                                @Override
                                public Integer load(Integer key) throws Exception {
                                    return 2;  // 当无值时, 设置默认值
                                }
                            }
                    );
            cache.put(1, 1);
            cache.put(2, 2);
            System.out.println(cache.asMap());  // 输出: {2=2, 1=1}
            cache.invalidateAll();
            System.out.println(cache.asMap());  // 输出: {}
            cache.put(3, 3);
            try {
                // 如果定义的CacheLoader没有声明任何检查型异常,则可以通过getUnchecked()取值
                System.out.println(cache.getUnchecked(3));  // 输出: 3
                Thread.sleep(3000);
                System.out.println(cache.getUnchecked(3));  // 输出: 2
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    

    7. 统计功能

        public void test8() {
            /**
             * hitCount;  // 缓存命中数
             * missCount; // 缓存未命中数
             * loadSuccessCount; // load成功数
             * loadExceptionCount; // load异常数
             * totalLoadTime; // load的总共耗时
             * evictionCount; // 缓存项被回收的总数,不包括显式清除
             */
            // 开启统计,并查看统计信息
            LoadingCache<String, String> cache = CacheBuilder.newBuilder()
                    .recordStats()  // 开启统计功能
                    .refreshAfterWrite(2, TimeUnit.SECONDS)  // 缓存写入2s后更新
                    .build(new CacheLoader<String, String>() {
                        @Override
                        public String load(String key) throws Exception {
                            return UUID.randomUUID().toString();
                        }
                    });
            cache.put("1", "a");
            System.out.println(cache.asMap());  // 输出: {1=a}
            System.out.println(cache.stats());  // 输出: CacheStats{hitCount=0, missCount=0, loadSuccessCount=0, loadExceptionCount=0, totalLoadTime=0, evictionCount=0}
            cache.getIfPresent("2");
            System.out.println(cache.asMap());  // 输出: {1=a}
            System.out.println(cache.stats());  // 输出: CacheStats{hitCount=0, missCount=1, loadSuccessCount=0, loadExceptionCount=0, totalLoadTime=0, evictionCount=0}
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //此处缓存里的值都是过期了的
            cache.getIfPresent("1");
            System.out.println(cache.asMap());  // 输出: {1=0207bb01-7b3c-4b66-b575-9fb2c5511a96}
            System.out.println(cache.stats());  // 输出: CacheStats{hitCount=1, missCount=1, loadSuccessCount=1, loadExceptionCount=0, totalLoadTime=21118733, evictionCount=0}
        }
    

    相关文章

      网友评论

          本文标题:Guava-CacheLoader

          本文链接:https://www.haomeiwen.com/subject/dxbsdrtx.html