Guava学习之Guava cache

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

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

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

1.CPU缓存

2.操作系统缓存

3.本地缓存

4.分布式缓存

5.HTTP缓存

6.数据库缓存

等等,可以说在计算机和网络领域,缓存无处不在。可以这么说,只要有硬件性能不对等,涉及到网络传输的地方都会有缓存的身影。

Guava Cache是一个全内存的本地缓存实现,它提供了线程安全的实现机制。整体上来说Guava cache 是本地缓存的不二之选,简单易用,性能好。当然如果你希望在分布式系统中使用缓存,那么还是需要Memcache来解决问题。

Guava Cache有两种:

1. CacheLoader

2. Cache

区别在于Cache并不会自动处理加载缓存,定制程度较高。

创建方式:

1. cacheLoader

2. callable callback

通过这两种方法创建的cache,和通常用map来缓存的做法比,有一个明显的特点–两种方法都实现了一种逻辑–从缓存中取key X的值,如果该值已经缓存过了,则返回缓存中的值,如果没有缓存过,可以通过某个方法(也就是业务上返回数据的逻辑)来获取这个值。guava提供的这两种方法的区别在于,cacheloader的定义比较宽泛,是针对整个cache定义的,可以认为是统一的根据key值load value的方法。而callable的方式较为灵活,允许你在get的时候指定。

cacheLoader方式实现实例:

 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的常用方法:

回收(Evictions):

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)