以前我也没想过使用堆缓存或者使用堆外缓存,如果这对你是个知识盲区?
Guava Cache网上一搜有很多的教程,阐述了它的各种用法,我只是想将这些Guava Cache的知识压缩一下,连成一条线,轻松的记住。
场景
由于它是JVM内存级别的缓存,特点就是快,缺点嘛也多,内存有限,垃圾回收问题,分布式问题等等。
适合存放少量,高频访问的数据。
使用
存与读
创建一个Cache容器
1 2 3 4 5 6 7
| private Cache<String, User> cache = CacheBuilder.newBuilder() .build(new CacheLoader<String, User>() { @Override public User load(String key) throws Exception { return null; } });
|
想容器中存储数据
1
| cache.put("apple", new User("apple", 1));
|
从Cache中读取数据
1 2 3 4
| public void test1() { User u = cache.getIfPresent("apple"); assertEquals(1, u.getAge()); }
|
刷新
之前在看亿级流量那本书里面提到了缓存用法中,有一种用法是Read-Through,意思是获取数据时,直接请求缓存,如果命中缓存则从缓存中返回,否则回源的数据源地址查询。
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
| LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder() .maximumSize(1000) .refreshAfterWrite(1, TimeUnit.MINUTES) .build( @Override new CacheLoader<Key, Graph>() { public Graph load(Key key) { return getGraphFromDatabase(key); } @Override public ListenableFuture<Graph> reload(final Key key, Graph prevGraph) { if (neverNeedsRefresh(key)) { return Futures.immediateFuture(prevGraph); } else { ListenableFutureTask<Graph> task = ListenableFutureTask.create(new Callable<Graph>() { public Graph call() { return getGraphFromDatabase(key); } }); executor.execute(task); return task; } } });
|
这个是文档中给出的示例,就是采用这种Read-Through的方法使用缓存
上述的代码指定了刷新的时间每分钟,刷新没成功前,会返回旧值。
清理
Guava提供了多种清理策略
大小
这个大小还需要自己算–
1 2 3 4 5 6 7 8 9 10 11 12 13
| LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder() .maximumWeight(100000) .weigher(new Weigher<Key, Graph>() { public int weigh(Key k, Graph g) { return g.vertices().size(); } }) .build( new CacheLoader<Key, Graph>() { public Graph load(Key key) { return createExpensiveGraph(key); } });
|
数量
按照缓存key数量 .maximumSize(3)
最近使用
expireAfterAccess(long, TimeUnit)
最近写时间
expireAfterWrite(long, TimeUnit)
垃圾回收器清理
通过设置K和V为弱引用的方法,让垃圾回收器进行回收
- CacheBuilder.weakKeys()
- CacheBuilder.weakValues()
- CacheBuilder.softValues() 软引用: 我也没懂
手动清理
- Cache.invalidate(key)
- Cache.invalidateAll(keys)
- Cache.invalidateAll()
最后,可以添加Remove监听来收到数据清理时的通知
1 2 3 4
| CacheBuilder.newBuilder() .expireAfterWrite(2, TimeUnit.MINUTES) .removalListener(removalListener) .build(loader);
|
统计
打开统计
1
| CacheBuilder.recordStats()
|
获得统计数据
1
| CacheStats cacheStats = cache.stats();
|
参考
1. 官方文档
2. 中文翻译
3. Guava Cache用法介绍