缓存,在我们日常开发中是必不可少的一种解决性能问题的方法。简单的说,cache 就是为了提升系统性能而开辟的一块内存空间。

  缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用。在日常开发的很多场合,由于受限于硬盘IO的性能或者我们自身业务系统的数据处理和获取可能非常费时,当我们发现我们的系统这个数据请求量很大的时候,频繁的IO和频繁的逻辑处理会导致硬盘和CPU资源的瓶颈出现。缓存的作用就是将这些来自不易的数据保存在内存中,当有其他线程或者客户端需要查询相同的数据资源时,直接从缓存的内存块中返回数据,这样不但可以提高系统的响应时间,同时也可以节省对这些数据的处理流程的资源消耗,整体上来说,系统性能会有大大的提升。

  缓存在很多系统和架构中都用广泛的应用,例如:

  1.CPU缓存
  2.操作系统缓存
  3.本地缓存
  4.分布式缓存
  5.HTTP缓存
  6.数据库缓存
  等等,可以说在计算机和网络领域,缓存无处不在。可以这么说,只要有硬件性能不对等,涉及到网络传输的地方都会有缓存的身影。

  Guava Cache是一个全内存的本地缓存实现,它提供了线程安全的实现机制。整体上来说Guava cache 是本地缓存的不二之选,简单易用,性能好。

  Guava Cache有两种创建方式:

  1. cacheLoader
  2. callable callback

  通过这两种方法创建的cache,和通常用map来缓存的做法比,不同在于,这两种方法都实现了一种逻辑——从缓存中取key X的值,如果该值已经缓存过了,则返回缓存中的值,如果没有缓存过,可以通过某个方法来获取这个值。但不同的在于cacheloader的定义比较宽泛,是针对整个cache定义的,可以认为是统一的根据key值load value的方法。而callable的方式较为灵活,允许你在get的时候指定。

  cacheLoader方式实现实例:

    @Test
public void TestLoadingCache() throws Exception{
LoadingCache<String,String> cahceBuilder=CacheBuilder
.newBuilder()
.build(new CacheLoader<String, String>(){
@Override
public String load(String key) throws Exception {
String strProValue="hello "+key+"!";
return strProValue;
} }); System.out.println("jerry value:"+cahceBuilder.apply("jerry"));
System.out.println("jerry value:"+cahceBuilder.get("jerry"));
System.out.println("peida value:"+cahceBuilder.get("peida"));
System.out.println("peida value:"+cahceBuilder.apply("peida"));
System.out.println("lisa value:"+cahceBuilder.apply("lisa"));
cahceBuilder.put("harry", "ssdded");
System.out.println("harry value:"+cahceBuilder.get("harry"));
}

  输出:

jerry value:hello jerry!
jerry value:hello jerry!
peida value:hello peida!
peida value:hello peida!
lisa value:hello lisa!
harry value:ssdded

  callable callback的实现:

    @Test
public void testcallableCache()throws Exception{
Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();
String resultVal = cache.get("jerry", new Callable<String>() {
public String call() {
String strProValue="hello "+"jerry"+"!";
return strProValue;
}
});
System.out.println("jerry value : " + resultVal); resultVal = cache.get("peida", new Callable<String>() {
public String call() {
String strProValue="hello "+"peida"+"!";
return strProValue;
}
});
System.out.println("peida value : " + resultVal);
}   输出:
  jerry value : hello jerry!
  peida value : hello peida!

  cache的参数说明:

  回收的参数:
  1. 大小的设置:CacheBuilder.maximumSize(long)  CacheBuilder.weigher(Weigher)  CacheBuilder.maxumumWeigher(long)
  2. 时间:expireAfterAccess(long, TimeUnit) expireAfterWrite(long, TimeUnit)
  3. 引用:CacheBuilder.weakKeys() CacheBuilder.weakValues()  CacheBuilder.softValues()
  4. 明确的删除:invalidate(key)  invalidateAll(keys)  invalidateAll()
  5. 删除监听器:CacheBuilder.removalListener(RemovalListener)
  

  refresh机制:
  1. LoadingCache.refresh(K)  在生成新的value的时候,旧的value依然会被使用。
  2. CacheLoader.reload(K, V) 生成新的value过程中允许使用旧的value
  3. CacheBuilder.refreshAfterWrite(long, TimeUnit) 自动刷新cache

  基于泛型的实现:

    /**
* 不需要延迟处理(泛型的方式封装)
* @return
*/
public <K , V> LoadingCache<K , V> cached(CacheLoader<K , V> cacheLoader) {
LoadingCache<K , V> cache = CacheBuilder
.newBuilder()
.maximumSize(2)
.weakKeys()
.softValues()
.refreshAfterWrite(120, TimeUnit.SECONDS)
.expireAfterWrite(10, TimeUnit.MINUTES)
.removalListener(new RemovalListener<K, V>(){
@Override
public void onRemoval(RemovalNotification<K, V> rn) {
System.out.println(rn.getKey()+"被移除"); }})
.build(cacheLoader);
return cache;
} /**
* 通过key获取value
* 调用方式 commonCache.get(key) ; return String
* @param key
* @return
* @throws Exception
*/ public LoadingCache<String , String> commonCache(final String key) throws Exception{
LoadingCache<String , String> commonCache= cached(new CacheLoader<String , String>(){
@Override
public String load(String key) throws Exception {
return "hello "+key+"!";
}
});
return commonCache;
} @Test
public void testCache() throws Exception{
LoadingCache<String , String> commonCache=commonCache("peida");
System.out.println("peida:"+commonCache.get("peida"));
commonCache.apply("harry");
System.out.println("harry:"+commonCache.get("harry"));
commonCache.apply("lisa");
System.out.println("lisa:"+commonCache.get("lisa"));
}

  输出:

peida:hello peida!
harry:hello harry!
peida被移除
lisa:hello lisa!

  基于泛型的Callable Cache实现:

    private static Cache<String, String> cacheFormCallable = null; 

    /**
* 对需要延迟处理的可以采用这个机制;(泛型的方式封装)
* @param <K>
* @param <V>
* @param key
* @param callable
* @return V
* @throws Exception
*/
public static <K,V> Cache<K , V> callableCached() throws Exception {
Cache<K, V> cache = CacheBuilder
.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
return cache;
} private String getCallableCache(final String userName) {
try {
//Callable只有在缓存值不存在时,才会调用
return cacheFormCallable.get(userName, new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println(userName+" from db");
return "hello "+userName+"!";
}
});
} catch (ExecutionException e) {
e.printStackTrace();
return null;
}
} @Test
public void testCallableCache() throws Exception{
final String u1name = "peida";
final String u2name = "jerry";
final String u3name = "lisa";
cacheFormCallable=callableCached();
System.out.println("peida:"+getCallableCache(u1name));
System.out.println("jerry:"+getCallableCache(u2name));
System.out.println("lisa:"+getCallableCache(u3name));
System.out.println("peida:"+getCallableCache(u1name)); }

  输出:

peida from db
peida:hello peida!
jerry from db
jerry:hello jerry!
lisa from db
lisa:hello lisa!
peida:hello peida!

  说明:Callable只有在缓存值不存在时,才会调用,比如第二次调用getCallableCache(u1name)直接返回缓存中的值

  guava Cache数据移除:

  guava做cache时候数据的移除方式,在guava中数据的移除分为被动移除和主动移除两种。
  被动移除数据的方式,guava默认提供了三种方式:
  1.基于大小的移除:看字面意思就知道就是按照缓存的大小来移除,如果即将到达指定的大小,那就会把不常用的键值对从cache中移除。
  定义的方式一般为 CacheBuilder.maximumSize(long),还有一种一种可以算权重的方法,个人认为实际使用中不太用到。就这个常用的来看有几个注意点,
    其一,这个size指的是cache中的条目数,不是内存大小或是其他;
    其二,并不是完全到了指定的size系统才开始移除不常用的数据的,而是接近这个size的时候系统就会开始做移除的动作;
    其三,如果一个键值对已经从缓存中被移除了,你再次请求访问的时候,如果cachebuild是使用cacheloader方式的,那依然还是会从cacheloader中再取一次值,如果这样还没有,就会抛出异常
  2.基于时间的移除:guava提供了两个基于时间移除的方法
    expireAfterAccess(long, TimeUnit)  这个方法是根据某个键值对最后一次访问之后多少时间后移除
    expireAfterWrite(long, TimeUnit)  这个方法是根据某个键值对被创建或值被替换后多少时间移除
  3.基于引用的移除:
  这种移除方式主要是基于java的垃圾回收机制,根据键或者值的引用关系决定移除
  主动移除数据方式,主动移除有三种方法:
  1.单独移除用 Cache.invalidate(key)
  2.批量移除用 Cache.invalidateAll(keys)
  3.移除所有用 Cache.invalidateAll()
  如果需要在移除数据的时候有所动作还可以定义Removal Listener,但是有点需要注意的是默认Removal Listener中的行为是和移除动作同步执行的,如果需要改成异步形式,可以考虑使用RemovalListeners.asynchronous(RemovalListener, Executor)

Guava学习笔记:Guava cache的更多相关文章

  1. Guava学习笔记目录

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

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

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

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

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

  4. Guava学习笔记(一)概览

    Guava是谷歌开源的一套Java开发类库,以简洁的编程风格著称,提供了很多实用的工具类, 在之前的工作中应用过Collections API和Guava提供的Cache,不过对Guava没有一个系统 ...

  5. Guava学习笔记:Google Guava 类库简介

    http://www.cnblogs.com/peida/tag/Guava/ Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, cachin ...

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

    1,大纲 让我们来熟悉瓜娃,并体验下它的一些API,分成如下几个部分: Introduction Guava Collection API Guava Basic Utilities IO API C ...

  7. Guava学习笔记:Immutable(不可变)集合

    不可变集合,顾名思义就是说集合是不可被修改的.集合的数据项是在创建的时候提供,并且在整个生命周期中都不可改变. 为什么要用immutable对象?immutable对象有以下的优点: 1.对不可靠的客 ...

  8. Guava学习笔记(一):Maven

    <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifact ...

  9. Guava学习笔记(1):Optional优雅的使用null

    转自:http://www.cnblogs.com/peida/archive/2013/06/14/Guava_Optional.html 参考:[Google Guava] 1.1-使用和避免nu ...

随机推荐

  1. Linux下chkconfig命令详解 这个简单明了啊

    chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. 使用语法:chkconfig [--ad ...

  2. react8 组件之间的通信

    <body><!-- React 真实 DOM 将会插入到这里 --><div id="example"></div> <!- ...

  3. 【java并发】传统线程技术中创建线程的两种方式

    传统的线程技术中有两种创建线程的方式:一是继承Thread类,并重写run()方法:二是实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread.这两种方式 ...

  4. angularjs可交互的directive

    angularjs可交互的directive http://jsfiddle.net/revolunet/s4gm6/ directive开发上手练手,以注释的方式说明 html <body n ...

  5. 开始使用MarkDown写博客

    MarkDown 标题 #h1 ##h2 ###h3 h1 h2 h3 代码段 代码段缩进4个空格即可,如下: <div class="form-group"> < ...

  6. javaweb回顾第九篇EL表达式

    前言:关于EL表示式开发用的非常多,现在我们回顾一下关于如果去操作EL表达式 1:EL表达式语法 所有EL表达式都是由{开始}结束,表达式中用.和[]操作符来访问数据比喻${user.userName ...

  7. Android内存回收机制

    退出但不关闭: 这是Android对于Linux的优化.当 Android 应用程序退出时,并不清理其所占用的内存,Linux 内核进程也相应的继续存在,所谓“退出但不关闭”.从而使得用户调用程序时能 ...

  8. 前端工程师技能之photoshop巧用系列扩展篇——自动切图

    × 目录 [1]初始设置 [2]自动切图 前面的话 随着photoshop版本的不断升级,软件本身增加了很多新的功能,也为切图工作增加了很多的便利.photoshop最新的版本新增了自动切图功能,本文 ...

  9. 简单的小工具wordlight——让VS变量高亮起来

    前段时间一直在使用matlab,今天需要使用vs2008,而用惯了matlab,习惯了其中一项选中变量高亮的设置,突然回来使用VS,感到各种不适应,顿时想到了一个词:矫情 呵呵,于是在网上找各种插件, ...

  10. PHP的学习--PHP的引用

    引用是什么 在 PHP 中引用意味着用不同的名字访问同一个变量内容.这并不像 C 的指针,替代的是,引用是符号表别名.注意在 PHP 中,变量名和变量内容是不一样的,因此同样的内容可以有不同的名字.最 ...