博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Google Guava - Cache
阅读量:7018 次
发布时间:2019-06-28

本文共 7253 字,大约阅读时间需要 24 分钟。

hot3.png

一、简介

  Google Guava包含了Google的Java项目许多依赖的库,如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。本文只介绍其中的缓存部分。
  Guava Cache是一种本地缓存实现,支持多种缓存过期策略。性能好,简单易用。缓存在很多场景下都是很有用的。如,通过key获取一个value的花费的时间很多,而且获取的次数不止一次的时候,就应该考虑使用缓存。Guava Cache与ConcurrentMap很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除。而Guava Cache为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管LoadingCache 不回收元素,它也会自动加载缓存。

  Guava Cache适用于以下应用场景:

  • 系统的访问速度首要考虑,而内存空间为次要考虑。
  • 某些key对于的value会被查询多次。
  • 缓存中存放的数据总量不会超出内存的全部大小。

本文例子使用的guava 版本为guava-18.0.jar,下载地址如下:

二、Cache使用方式

  1、CacheLoader方式

  代码如下:

import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutionException;import java.util.concurrent.TimeUnit;import org.junit.Test;import com.google.cacahe.Person;import com.google.common.cache.CacheBuilder;import com.google.common.cache.CacheLoader;import com.google.common.cache.LoadingCache;public class TestGuavaCache {    @Test    public void testUserCacheLoader() throws ExecutionException {        // 模拟数据        final List
list = new ArrayList
(5); list.add(new Person("1", "zhangsan")); list.add(new Person("2", "lisi")); list.add(new Person("3", "wangwu")); // 创建cache LoadingCache
cache = CacheBuilder.newBuilder()// .refreshAfterWrite(1, TimeUnit.MINUTES)// 给定时间内没有被读/写访问,则回收。 // .expireAfterWrite(5, TimeUnit.SECONDS)//给定时间内没有写访问,则回收。 // .expireAfterAccess(3, TimeUnit.SECONDS)// 缓存过期时间为3秒 .maximumSize(100).// 设置缓存个数 build(new CacheLoader
() { @Override /** 当本地缓存命没有中时,调用load方法获取结果并将结果缓存 */ public Person load(String key) throws ExecutionException { System.out.println(key + " load in cache"); return getPerson(key); } // 此时一般我们会进行相关处理,如到数据库去查询 private Person getPerson(String key) throws ExecutionException { System.out.println(key + " query"); for (Person p : list) { if (p.getId().equals(key)) return p; } return null; } }); cache.get("1"); cache.get("2"); cache.get("3"); System.out.println("======= sencond time =========="); cache.get("1"); cache.get("2"); cache.get("3"); }}

执行结果如下:

load in cachequeryload in cachequeryload in cachequery======= sencond time  ==========

第二次获取的时候没有执行获取的方法,而是直接从缓存中获取。

  2、Callback方式

  代码如下:

import java.util.ArrayList;import java.util.List;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import org.junit.Test;import com.google.cacahe.Person;import com.google.common.cache.Cache;import com.google.common.cache.CacheBuilder;public class TestGuavaCache {        @Test    public void testUserCallback() throws ExecutionException {        // 模拟数据        final List
list = new ArrayList
(5); list.add(new Person("1", "zhangsan")); list.add(new Person("2", "lisi")); list.add(new Person("3", "wangwu")); final String key = "1"; Cache
cache2 = CacheBuilder.newBuilder().maximumSize(1000).build(); /** * 用缓存中的get方法,当缓存命中时直接返回结果;否则,通过给定的Callable类call方法获取结果并将结果缓存。
* 可以用一个cache对象缓存多种不同的数据,只需创建不同的Callable对象即可。 */ Person person = cache2.get(key, new Callable
() { public Person call() throws ExecutionException { System.out.println(key + " load in cache"); return getPerson(key); } // 此时一般我们会进行相关处理,如到数据库去查询 private Person getPerson(String key) throws ExecutionException { System.out.println(key + " query"); for (Person p : list) { if (p.getId().equals(key)) return p; } return null; } }); System.out.println("======= sencond time =========="); person = cache2.getIfPresent(key); person = cache2.getIfPresent(key); }}

执行结果如下:

1 load in cache1 query======= sencond time  ==========

第二次获取后也是直接从缓存中加载。

  3、关于移除监听器

  通过CacheBuilder.removalListener(RemovalListener),我们可以声明一个监听器,从而可以在缓存被移除时做一些其他的操作。当缓存被移除时,RemovalListener会获取移除bing通知[RemovalNotification],其中包含移除的key、value和RemovalCause。

  示例代码如下:

import java.util.concurrent.ExecutionException;import java.util.concurrent.TimeUnit;import org.junit.Test;import com.google.cacahe.Person;import com.google.common.cache.CacheBuilder;import com.google.common.cache.CacheLoader;import com.google.common.cache.LoadingCache;import com.google.common.cache.RemovalListener;import com.google.common.cache.RemovalNotification;public class TestGuavaCache {    @Test    public void testListener() throws ExecutionException {        CacheLoader
loader = new CacheLoader
() { @Override // 当本地缓存命没有中时,调用load方法获取结果并将结果缓存 public Person load(String key) throws ExecutionException { System.out.println(key + " load in cache"); return getPerson(key); } // 此时一般我们会进行相关处理,如到数据库去查询 private Person getPerson(String key) throws ExecutionException { System.out.println(key + " query"); return new Person(key, "zhang" + key); } }; // remove listener RemovalListener
removalListener = new RemovalListener
() { public void onRemoval(RemovalNotification
removal) { System.out.println("cause:" + removal.getCause() + " key:" + removal.getKey() + " value:" + removal.getValue()); } }; LoadingCache
cache = CacheBuilder.newBuilder()// .expireAfterWrite(2, TimeUnit.MINUTES).maximumSize(1024).removalListener(removalListener).build(loader); cache.get("1");// 放入缓存 cache.get("1");// 第二次获取(此时从缓存中获取) cache.invalidate("1");// 移除缓存 cache.get("1");// 重新获取 cache.get("1");// 再次获取(此时从缓存中获取) }}

运行结果如下:

1 1 load in cache2 1 query3 cause:EXPLICIT key:1 value:Person [id=1, name=zhang1]4 1 load in cache5 1 query

三、其他相关方法

  显式插入:该方法可以直接向缓存中插入值,如果缓存中有相同key则之前的会被覆盖。

cache.put(key, value);

显式清除:我们也可以对缓存进行手动清除。

cache.invalidate(key); //单个清除cache.invalidateAll(keys); //批量清除cache.invalidateAll(); //清除所有缓存项

基于时间的移除: 

expireAfterAccess(long, TimeUnit); 该键值对最后一次访问后超过指定时间再移除expireAfterWrite(long, TimeUnit) ;该键值对被创建或值被替换后超过指定时间再移除

基于大小的移除:指如果缓存的对象格式即将到达指定的大小,就会将不常用的键值对从cache中移除。

cacheBuilder.maximumSize(long)

size是指cache中缓存的对象个数。当缓存的个数开始接近size的时候系统就会进行移除的操作

  缓存清除执行的时间

  使用CacheBuilder构建的缓存不会"自动"执行清理和回收工作,也不会在某个缓存项过期后马上清理,也没有诸如此类的清理机制。它是在写操作时顺带做少量的维护工作(清理);如果写操作太少,读操作的时候也会进行少量维护工作。因为如果要自动地持续清理缓存,就必须有一个线程,这个线程会和用户操作竞争共享锁。在某些环境下线程创建可能受限制,这样CacheBuilder就不可用了。

转载于:https://my.oschina.net/u/2505806/blog/756260

你可能感兴趣的文章
即时通信增长持续放缓,差异化与多元化成为趋势
查看>>
《认知设计:提升学习体验的艺术》——与学习者进行交流
查看>>
默认OpenStack安全组:如何更改规则?
查看>>
调查:网络提供商不能有效抵御DDoS攻击
查看>>
人工智能+人=强大的网络安全
查看>>
Office 2016七月更新:Word和Outlook更智能,PowerPoint新动效
查看>>
“十三五”公共安全科技创新规划涉及哪些安防概念?
查看>>
AI 科技评论和学术青年们的 GAIR 小聚会,面基就要freestyle|CCF-GAIR 2017
查看>>
国内首个14纳米硅片凸块量产 高通高端芯片“中国造”
查看>>
“Watson之眼”走出实验室,中国医疗机器人悄然崛起 | 未来医疗周刊
查看>>
依托大数据,医改要有基于标准体系的资源配置
查看>>
抢夺英特尔Mac订单 AMD拦路虎暂不成气候
查看>>
没落的雅达利要分智能家居市场一杯羹 有点晚
查看>>
晋能科技高效多晶组件助力吕梁多个扶贫项目顺利并网
查看>>
AI运算存储器需求仍靠外供 大数据或孕育新市场
查看>>
五大气象引领物联网发展新高潮,但政府角色需调整
查看>>
数据中心选址需要明智的决策
查看>>
Windows 10“创作者更新”改进了高DPI缩放支持
查看>>
选择公共云供应商的标准
查看>>
中兴微电子2016年蝉联IC设计企业前三,芯片发货量大幅增长
查看>>