Guava Cache使用笔记

编程技术  /  houtizong 发布于 3年前   215
1.Guava Cache的get/getIfPresent方法当参数为null时会抛空指针异常

我刚开始使用时还以为Guava Cache跟HashMap一样,get(null)返回null。
实际上Guava整体设计思想就是拒绝null的,很多地方都会执行com.google.common.base.Preconditions.checkNotNull的检查。

2.Guava Cache的load方法不能返回null,否则抛异常

Guava Cache的get方法先在本地缓存中取,如果不存在,则会触发load方法。但load方法不能返回null。

设想这样一个场景:进行某些热点数据查询时,如果缓存中没有,则去数据库中查询,并把查询到的结果保存到缓存中。
但假如说数据库中也没有呢?
这个时候load方法就会抛异常,例如:
public enum TestGuavaCache {    INSTANCE;    private LoadingCache<String, Person> infos;    TestGuavaCache() {        infos = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES).build(new CacheLoader<String, Person>() {            public Person load(String key) throws Exception {                //load from database                Person p = loadFromDatabase();                return p;            }        });    }//假设数据库中不存在    private Person loadFromDatabase() {        return null;    }    public Person get(String key) {        try {            return infos.get(key);        } catch (Exception e) {            //log exception        }        return null;    }}

这是因为Guava Cache认为cache null是无意义的,因此Guava Cache的javadoc里加粗说明:must not be null

现实世界没那么理想,肯定会有null的情况,那怎么处理呢?我的处理一般是对Guava Cache的get方法做try-catch。


有时候cache null也是有意义的,例如对于一个key,假如数据库中也没有对应的value,那就把这个情况记录下来,
避免频繁的查询数据库(例如一些攻击性行为),直接在缓存中就把这个key挡住了。
怎么做呢?举例:

@Testpublic void whenNullValue_thenOptional() {    CacheLoader<String, Optional<String>> loader;    loader = new CacheLoader<String, Optional<String>>() {        @Override        public Optional<String> load(String key) {            return Optional.fromNullable(getSuffix(key));        }    };     LoadingCache<String, Optional<String>> cache;    cache = CacheBuilder.newBuilder().build(loader);     assertEquals("txt", cache.getUnchecked("text.txt").get());    assertFalse(cache.getUnchecked("hello").isPresent());}private String getSuffix(final String str) {    int lastIndex = str.lastIndexOf('.');    if (lastIndex == -1) {        return null;    }    return str.substring(lastIndex + 1);}


3.什么时候用get,什么时候用getUnchecked

官网文档说:
. If you have defined a CacheLoader that does not declare any checked exceptions then you can perform cache lookups using getUnchecked(K); however care must be taken not to call getUnchecked on caches whose CacheLoaders declare checked exceptions.

字面意思是,如果你的CacheLoader没有定义任何checked Exception,那你可以使用getUnchecked。
这一段话我也不是很理解。。官网上给了一个例子是,load方法没有声明throws Exception,那就可以使用getUnchecked:
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()       .expireAfterAccess(10, TimeUnit.MINUTES)       .build(           new CacheLoader<Key, Graph>() {             public Graph load(Key key) { // no checked exception               return createExpensiveGraph(key);             }           });...return graphs.getUnchecked(key);


4.如何定义一个普通的Guava Cache,不需要用到load方法

假如只是简单的把Guava Cache当作HashMap或ConcurrentHashMap的替代品,不需要用到load方法,而是手动地插入,可以这样:
com.google.common.cache.Cache<String, String> cache = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).build();

注意不能用LoadingCache了。
查找:
cache.getIfPresent("xx");
插入:
cache.put("xx", "xxx");

5.Guava Cache的超时机制不是精确的。

我曾经依赖Guava Cache的超时机制和RemovalListener,以实现类似定时任务的功能;后来发现Guava Cache的超时机制是不精确的,例如你设置cache的缓存时间是30秒,
那它存活31秒、32秒,都是有可能的。
官网说:
Timed expiration is performed with periodic maintenance during writes and occasionally during reads, as discussed below.Caches built with CacheBuilder do not perform cleanup and evict values "automatically," or instantly after a value expires, or anything of the sort. Instead, it performs small amounts of maintenance during write operations, or during occasional read operations if writes are rare.





请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客