Guava的缓存是本地缓存,所以我觉得在使用场景上适合那种并非是高一致性的场景中,而且他的实现和ConcurrentHashMap很类似。但是毕竟是缓存嘛,肯定有自动清除的功能。外加一些什么清除策略等等。

我们看guava的cache包下面也就是才十几个类,所以可以说知识一个基础工具,如果要使用到生产环境中去的话,那么还需要我们好好的进一步封装。

最主要的一个类就是LoadingCache,主要的创建方式也是很常见的构造器方式。

    @Test
public void defaultCache(){ LoadingCache<String, Integer> cache=CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterAccess(10, TimeUnit.SECONDS)
//默认情况下 监听器是和移除操作是同步的 但是可以使用RemovalListeners.asynchronous 设置为异步
.removalListener(RemovalListeners.asynchronous(new RemovalListenerImpl() {
}, Executors.newCachedThreadPool()))
.build(
new CacheLoader<String, Integer>(){ @Override
public Integer load(String key) throws Exception {
return loadValue();
}
}
);

主要的几个参数最大值  过期时间,移除缓存的操作,加载缓存的操作(CacheLoader).

CacheLoader 

缓存的加载器,我们可以通过实现load()方法,通过key来加载value,如果值一旦加载完了之后,如果值没有失效并且没有被取代的话,那么下次根据这个KEY来获取值的话,那么就直接返回缓存中的值了。其他还有很多方法,比如reload()重载方法时调用,静态方法asyncReloading(...)对自定义的CacheLoader进行装饰,返回一个异步处理加载缓存发CacheLoader

获取缓存

1.

至于获取缓存,那么直接使用cache.get(key)就ok啦,但是当我们使用这个方法的时候,返回会抛出一个受检查的异常,这是因为我们在加载value的时候,会有可能抛出异常(load方法),这个要取决我们自己,如果我们方法没有排除异常的话,像这样:

                    new CacheLoader<String, Integer>(){

                        @Override
public Integer load(String key){ return loadValue();
}
}

那么就可以不使用cache.get(key),而采用cache.getUnchecked(key),那么我们就不用处理异常

2.

还有第二种方式加载缓存,就是使用Callable,但是如果我们自己也实现了CacheLoader的话,那么就会把这个逻辑给覆盖掉。如果要使用这种方式的哈,那么应该这样:

        Cache<String, Integer> cache=CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterAccess(10, TimeUnit.SECONDS)
//默认情况下 监听器是和移除操作的同步的 但是可以使用RemovalListeners.asynchronous 设置为异步
.removalListener(RemovalListeners.asynchronous(new RemovalListenerImpl() {
}, Executors.newCachedThreadPool()))
.build();

显式插入

对于有一些场景 我们可能会一开始就将缓存加载到进去,那么之后获取的时候,就不需要那么麻烦的进行每次没有命中的时候,重新的计算。这个时候我们可以使用显式的加载缓存,

        //这个map将反应到缓存的中的项中  但是不能保证其的原子性
cache.asMap().putIfAbsent("1", 1);
cache.put("2", 2); //一般都优先的使用这种方式

其中asMap()方式返回一个缓存中的视图,我们也可以在上面进行操作,但是个人建议是只能拿来进行缓存的获取,不要拿来进行显式的插入,毕竟不是原子性的!

缓存回收的策略

基于容量最大值来进行回收

也就是缓存到达了一定数量之后,或者数量逼近的时候,那么就开始进行缓存的回收

.maximumSize(100)

基于权重的方式。权重越接近,那么就越接近回收

          .maximumWeight(100)
.weigher(new Weigher<String, Integer>() { public int weigh(String key, Integer value) { if("100".equals(key))
return 100; return 0;
}
})

定时回收,...Access 表示的是读写都会刷新时间   ...Write表示的是写入之后开始计时

.expireAfterAccess(3, TimeUnit.MINUTES)
.expireAfterWrite(10, TimeUnit.MINUTES)

基于引用的回收(Reference-based Eviction)

通过使用弱引用的键、或弱引用的值、或软引用的值,Guava Cache可以把缓存设置为允许垃圾回收

CacheBuilder.weakKeys():使用弱引用存储键。当键没有其它(强或软)引用时,缓存项可以被垃圾回收。因为垃圾回收仅依赖恒等式(==),使用弱引用键的缓存用==而不是equals比较键。

CacheBuilder.weakValues():使用弱引用存储值。当值没有其它(强或软)引用时,缓存项可以被垃圾回收。因为垃圾回收仅依赖恒等式(==),使用弱引用值的缓存用==而不是equals比较值。

CacheBuilder.softValues():使用软引用存储值。软引用只有在响应内存需要时,才按照全局最近最少使用的顺序回收。考虑到使用软引用的性能影响,我们通常建议使用更有性能预测性的缓存大小限定(见上文,基于容量回收)。使用软引用值的缓存同样用==而不是equals比较值

显式清除

任何时候,你都可以显式地清除缓存项,而不是等到它被回收:

个别清除:Cache.invalidate(key)
批量清除:Cache.invalidateAll(keys)
清除所有缓存项:Cache.invalidateAll()

刷新缓存

刷新和回收不太一样。正如LoadingCache.refresh(K)所声明,刷新表示为键加载新值,这个过程可以是异步的。在刷新操作进行时,缓存仍然可以向其他线程返回旧值,而不像回收操作,读缓存的线程必须等待新值加载完成。

如果刷新过程抛出异常,缓存将保留旧值,而异常会在记录到日志后被丢弃[swallowed]。

重载CacheLoader.reload(K, V)可以扩展刷新时的行为,这个方法允许开发者在计算新值时使用旧的值。

统计

CacheBuilder.recordStats()用来开启Guava Cache的统计功能。统计打开后,Cache.stats()方法会返回CacheStats对象以提供如下统计信息:

  hitRate():缓存命中率;
  averageLoadPenalty():加载新值的平均时间,单位为纳秒;
  evictionCount():缓存项被回收的总数,不包括显式清除。

中断:

缓存加载方法(如Cache.get)不会抛出InterruptedException。我们也可以让这些方法支持InterruptedException,但这种支持注定是不完备的,并且会增加所有使用者的成本,而只有少数使用者实际获益。详情请继续阅读。

Cache.get请求到未缓存的值时会遇到两种情况:当前线程加载值;或等待另一个正在加载值的线程。这两种情况下的中断是不一样的。等待另一个正在加载值的线程属于较简单的情况:使用可中断的等待就实现了中断支持;但当前线程加载值的情况就比较复杂了:因为加载值的CacheLoader是由用户提供的,如果它是可中断的,那我们也可以实现支持中断,否则我们也无能为力。

如果用户提供的CacheLoader是可中断的,为什么不让Cache.get也支持中断?从某种意义上说,其实是支持的:如果CacheLoader抛出InterruptedException,Cache.get将立刻返回(就和其他异常情况一样);此外,在加载缓存值的线程中,Cache.get捕捉到InterruptedException后将恢复中断,而其他线程中InterruptedException则被包装成了ExecutionException。

原则上,我们可以拆除包装,把ExecutionException变为InterruptedException,但这会让所有的LoadingCache使用者都要处理中断异常,即使他们提供的CacheLoader不是可中断的。如果你考虑到所有非加载线程的等待仍可以被中断,这种做法也许是值得的。但许多缓存只在单线程中使用,它们的用户仍然必须捕捉不可能抛出的InterruptedException异常。即使是那些跨线程共享缓存的用户,也只是有时候能中断他们的get调用,取决于那个线程先发出请求。

对于这个决定,我们的指导原则是让缓存始终表现得好像是在当前线程加载值。这个原则让使用缓存或每次都计算值可以简单地相互切换。如果老代码(加载值的代码)是不可中断的,那么新代码(使用缓存加载值的代码)多半也应该是不可中断的。

如上所述,Guava Cache在某种意义上支持中断。另一个意义上说,Guava Cache不支持中断,这使得LoadingCache成了一个有漏洞的抽象:当加载过程被中断了,就当作其他异常一样处理,这在大多数情况下是可以的;但如果多个线程在等待加载同一个缓存项,即使加载线程被中断了,它也不应该让其他线程都失败(捕获到包装在ExecutionException里的InterruptedException),正确的行为是让剩余的某个线程重试加载。为此,我们记录了一个bug。然而,与其冒着风险修复这个bug,我们可能会花更多的精力去实现另一个建议AsyncLoadingCache,这个实现会返回一个有正确中断行为的Future对象。

Guava学习-缓存的更多相关文章

  1. [Google Guava]学习--缓存cache

    适用性 缓存在很多情况下非常实用.例如,计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存. Guava Cache与ConcurrentMap很相似,但也不完全 ...

  2. spring boot guava cache 缓存学习

    http://blog.csdn.net/hy245120020/article/details/78065676 ****************************************** ...

  3. guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用

    guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用 1,大纲 让我们来熟悉瓜娃,并体验下它的一些API,分成如下几个部分: Introduction Guava Collection ...

  4. Guava学习笔记目录

    Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libra ...

  5. guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁

    guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁 1,本文翻译自 http://eclipsesource.com/blogs/2012/06/06/cleaner-code- ...

  6. Guava学习

    Guava学习笔记目录 Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concu ...

  7. [置顶] Guava学习之ArrayListMultimap

    ArrayListMultimap类的继承关系如下图所示: Guava ArrayListMultimap List Multimap 是一个接口,继承自 Multimap 接口.ListMultim ...

  8. [置顶] Guava学习之Splitter

    Splitter:在Guava官方的解释为:Extracts non-overlapping substrings from an input string, typically by recogni ...

  9. [置顶] Guava学习之Iterators

    Iterators类提供了返回Iterator类型的对象或者对Iterator类型对象操作的方法.除了特别的说明,Iterators类中所有的方法都在Iterables类中有相应的基于Iterable ...

随机推荐

  1. IEEE754、VAX、IBM浮点型介绍和.NET中互相转换

    [题外话] 最近在做C3D文件的解析,好奇怪的是文件中竟然存储了CPU的类型,原本不以为然,结果后来读取一个文件发现浮点数全部读取错误.查了下发现虽然在上世纪80年代就提出了IEEE754要统一浮点数 ...

  2. Linux LVM逻辑卷

    概述 LVM的产生是因为传统的分区一旦分区好后就无法在线扩充空间,也存在一些工具能实现在线扩充空间但是还是会面临数据损坏的风险:传统的分区当分区空间不足时,一般的解决办法是再创建一个更大的分区将原分区 ...

  3. 垃圾回收机制GC知识再总结兼谈如何用好GC

    一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...

  4. 《Entity Framework 6 Recipes》中文翻译系列 (38) ------ 第七章 使用对象服务之动态创建连接字符串和从数据库读取模型

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第七章 使用对象服务 本章篇幅适中,对真实应用中的常见问题提供了切实可行的解决方案. ...

  5. Socket programing(make a chat software) summary 1:How to accsess LAN from WAN

    First we should know some basic conceptions about network: 1.Every PC is supposed to have its own IP ...

  6. [Canvas前端游戏开发]——FlappyBird详解

    一直想自己做点小东西,直到最近看了本<HTML5游戏开发>,才了解游戏开发中的一点点入门知识. 本篇就针对学习的几个样例,自己动手实践,做了个FlappyBird,源码共享在度盘 :也可以 ...

  7. LinQ to entities 不能识别方法“system.string.ToString(system.String)”.因此该方法无法转换为存储表达式

    [我也是刚研究IEnumerable和IQueryable]以下都是个人理解,仅供参考,如有错误欢迎指出~ 在EF里面,使用IQueryable和IEnumerable可以延迟加载. IQueryba ...

  8. ExtJs4常用配置方法备忘

    viewport布局常用属性 new Ext.Viewport({ layout: "border", renderTo: Ext.getBody(), defaults: { b ...

  9. OpenCASCADE Linear Extrusion Surface

    OpenCASCADE Linear Extrusion Surface eryar@163.com Abstract. OpenCASCADE linear extrusion surface is ...

  10. javascript运动系列第四篇——抖动

    × 目录 [1]原理介绍 [2]代码实现 [3]实例应用 前面的话 在运动系列中,前面分别介绍了匀速运动.变速运动和曲线运动.下面介绍一种特殊的运动形式——抖动 原理介绍 抖动其实是往复运动的一种特殊 ...