GUAVA-cache实现

GUAVA  Cache

Guava Cache与ConcurrentMap很相似基于分段锁及线程安全,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除。相对地,Guava Cache为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管LoadingCache 不回收元素,它也是很有用的,因为它会自动加载缓存。

适用场景

1)可以接受消耗内存来提高性能

2)某些key会被多次查询

3)缓存中的数据量不会超出内存容量

使用案例

package com.guava.cache;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import org.junit.Test;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
/**
 *
 * @author gaojiayi
 *
 */
public class TestCache {
  //基于loadingCache加载
  //@Test
  public void TestLoadingCache() throws Exception{
      LoadingCache<String,String> cahceBuilder=CacheBuilder
      .newBuilder()
      .build(new CacheLoader<String, String>(){
        //提供默认的加载加载方式,在实际生产中,可以选择从DB中,或者文件中加载相应的value
          @Override
          public String load(String key) throws Exception {
              String strProValue="hello "+key+"!";
              return strProValue;
          }
          //批量加载
          @Override
          public Map<String, String> loadAll(Iterable<? extends String> keys) throws Exception {
            // TODO Auto-generated method stub
            Map<String, String> retMap = new HashMap<String, String>();
            for(String key: keys){
              retMap.put(key, load(key));
            }
            return retMap;
          }

      });        

      System.out.println("jerry value:"+cahceBuilder.apply("jerry"));
    //get(K)方法,这个方法要么返回已经缓存的值,要么使用CacheLoader向缓存原子地加载新值。
      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"));
      //使用cache.put(key, value)方法可以直接向缓存中插入值,这会直接覆盖掉给定键之前映射的值
      cahceBuilder.put("harry", "ssdded");
      System.out.println("harry value:"+cahceBuilder.get("harry"));

      System.out.println("________________________________________");
      List<String> list = new ArrayList<>();
      list.add("1");
      list.add("2");
      System.out.println(cahceBuilder.getAll(list));
  }

  //基于Callable加载
  @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);
  }
}

缓存回收

使用CacheBuilder构建的缓存不会"自动"执行清理和回收工作,也不会在某个缓存项过期后马上清理,也没有诸如此类的清理机制。相反,它会在写操作时顺带做少量的维护工作,或者偶尔在读操作时做——如果写操作实在太少的话。

这样做的原因在于:如果要自动地持续清理缓存,就必须有一个线程,这个线程会和用户操作竞争共享锁。此外,某些环境下线程创建可能受限制,这样CacheBuilder就不可用了。

相反,我们把选择权交到你手里。如果你的缓存是高吞吐的,那就无需担心缓存的维护和清理等工作。如果你的 缓存只会偶尔有写操作,而你又不想清理工作阻碍了读操作,那么可以创建自己的维护线程,以固定的时间间隔调用Cache.cleanUp()ScheduledExecutorService可以帮助你很好地实现这样的定时调度。

基于容量的回收

CacheBuilder.maximumSize(long)

基于权重回收

 //。在权重限定场景中,除了要注意回收也是在重量逼近限定值时就进行了,
    //还要知道重量是在缓存创建时计算的,因此要考虑重量计算的复杂度。
      Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000)
          .maximumWeight(100)
          .weigher(new Weigher<String,String>(){

            @Override
            public int weigh(String key, String value) {
              // TODO Auto-generated method stub
              return value.getBytes().length;
            }

          }).build();  

定时回收

  • expireAfterAccess(long, TimeUnit):缓存项在给定时间内没有被读/写访问,则回收。请注意这种缓存的回收顺序和基于大小回收一样。
  • expireAfterWrite(long, TimeUnit):缓存项在给定时间内没有被写访问(创建或覆盖),则回收。如果认为缓存数据总是在固定时候后变得陈旧不可用,这种回收方式是可取的。

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

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

  • CacheBuilder.weakKeys():使用弱引用存储键。当键没有其它(强或软)引用时,缓存项可以被垃圾回收。因为垃圾回收仅依赖恒等式(==),使用弱引用键的缓存用==而不是equals比较键。
  • CacheBuilder.weakValues():使用弱引用存储值。当值没有其它(强或软)引用时,缓存项可以被垃圾回收。因为垃圾回收仅依赖恒等式(==),使用弱引用值的缓存用==而不是equals比较值。
  • CacheBuilder.softValues():使用软引用存储值。软引用只有在响应内存需要时,才按照全局最近最少使用的顺序回收。考虑到使用软引用的性能影响,我们通常建议使用更有性能预测性的缓存大小限定(见上文,基于容量回收)。使用软引用值的缓存同样用==而不是equals比较值。

显式清除

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

刷新reload

      LoadingCache<String,String> cahceBuilder=CacheBuilder
      .newBuilder()
      //注意:缓存并不会因为刷新盲目地定时重置,如果缓存项没有被检索,那刷新就不会真的发生,
      //(可以理解未异步定时获取新增,而不会做刷新,只有被检索时才会真正刷新)
      //如果设置过期(expireAfterWrite)缓存项在过期时间后也变得可以回收。
      .refreshAfterWrite(2, TimeUnit.MINUTES)
      .build(new CacheLoader<String, String>(){
        //提供默认的加载加载方式,在实际生产中,可以选择从DB中,或者文件中加载相应的value
          @Override
          public String load(String key) throws Exception {
              String strProValue="hello "+key+"!";
              return strProValue;
          }
          //重新加载:重载CacheLoader.reload(K, V)可以扩展刷新时的行为,这个方法允许开发者在计算新值时使用旧的值。
          @Override
          public ListenableFuture<String> reload(String key, String oldValue) throws Exception {
            // TODO Auto-generated method stub
            return super.reload(key, oldValue);
          }

      });        

删除操作监听

 Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000)
          .removalListener(new RemovalListener<String,String>(){

            @Override
            public void onRemoval(RemovalNotification<String, String> removalnotification) {
              // 释放资源

            }})

参考:http://www.cnblogs.com/peida/p/Guava_Cache.html

时间: 2024-11-06 02:20:41

GUAVA-cache实现的相关文章

guava cache与spring集成

缓存的背景 缓存,在我们日常开发中是必不可少的一种解决性能问题的方法.简单的说,cache 就是为了提升系统性能而开辟的一块内存空间.在cpu进行计算的时候, 首先是读取寄存器,然后内存,再是硬盘.由于寄存器容量很小,不太适合存储我们需要快速读取的数据,放在硬盘中话,效率太低,所以大多数人将一些静态资源或者不经常修改的数据放在内存中. 缓存的作用 缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用.在日常开发的很多场合,由于受限于硬盘 IO的性能或者我们自身业务系统的数

缓存框架Guava Cache部分源码分析

在本地缓存中,最常用的就是OSCache和谷歌的Guava Cache.其中OSCache在07年就停止维护了,但它仍然被广泛的使用.谷歌的Guava Cache也是一个非常优秀的本地缓存,使用起来非常灵活,功能也十分强大,可以说是当前本地缓存中最优秀的缓存框架之一.之前我们分析了OSCache的部分源码,本篇就通过Guava Cache的部分源码,来分析一下Guava Cache的实现原理. 在分析之前,先弄清数据结构的使用.之前的文章提到,OSCache使用了一个扩展的HashTable,作

google guava cache

老规矩,有些知识很容易忘记啊,还是记录一下咯. google guava cache中,有很多参数. 1.expireAfterAccess(n , timeunit)   表示cache中管理的key如果在n(s,m,h,d)时间范围内没有被使用,则被cache驱逐. 2.maximumSize(n)   表示可以缓存的最大数目.没有到达最大数目时, 即开始驱逐部门缓存数据. 3.removalListener     实现RemovalListener接口onRemoval方法.可以记录缓存

第二章 Google guava cache源码解析1--构建缓存器

1.guava cache 当下最常用最简单的本地缓存 线程安全的本地缓存 类似于ConcurrentHashMap(或者说成就是一个ConcurrentHashMap,只是在其上多添加了一些功能) 2.使用实例 具体在实际中使用的例子,去查看<第七章 企业项目开发--本地缓存guava cache>,下面只列出测试实例: import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit;

(翻译)Google Guava Cache

翻译自Google Guava Cache This Post is a continuation of my series on Google Guava, this time covering Guava Cache. Guava Cache offers more flexibility and power than either a HashMap or ConcurrentHashMap, but is not as heavy as using EHCache or Memcache

Guava学习笔记:Guava cache

缓存,在我们日常开发中是必不可少的一种解决性能问题的方法.简单的说,cache 就是为了提升系统性能而开辟的一块内存空间. 缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用.在日常开发的很多场合,由于受限于硬盘IO的性能或者我们自身业务系统的数据处理和获取可能非常费时,当我们发现我们的系统这个数据请求量很大的时候,频繁的IO和频繁的逻辑处理会导致硬盘和CPU资源的瓶颈出现.缓存的作用就是将这些来自不易的数据保存在内存中,当有其他线程或者客户端需要查询相同的数据资源时,

Guava库学习:学习Guava Cache知识汇总

原文地址:Guava库学习:学习Guava Cache知识汇总 至此,我们结束了对Guava Cache 缓存机制的学习,在学习过程中,我们学习了如何简单的通过MapMaker创建最简单的ConcurrentMap缓存,我们也了解了缓存的高级特性,以及强大的LoadingCache,我们也探索和学习了CacheBuilder.CacheLoader这些核心的API,以及CacheStats.RemovalLitener等,下面对这些文章做一些汇总,方便以后的查阅和复习.     Guava库学习

Java 高并发缓存与Guava Cache

一.背景 缓存是我们在开发中为了提高系统的性能,把经常的访问业务的数据第一次把处理结果先放到缓存中,第二次就不用在对相同的业务数据在重新处理一遍,这样就提高了系统的性能.缓存分好几种: (1)本地缓存. (2)数据库缓存. (3)分布式缓存. 分布式缓存比较常用的有memcached等,memcached是高性能的分布式内存缓存服务器,缓存业务处理结果,减少数据库访问次数和相同复杂逻辑处理的时间,以提高动态Web应用的速度. 提高可扩展性. 二.本地缓存在高并发下的问题以及解决 今天我们介绍的是

guava cache使用例子

关于介绍请参考:http://blog.csdn.net/liangrui1988/article/details/46120533# 下面是测试代码 ,下载源码可在github上获取:https://github.com/liangrui1988/guavaTest package org.rui.test; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import

Guava库学习:学习Guava Cache(六)CacheStats

原文地址:Guava库学习:学习Guava Cache(六)CacheStats 上一篇,Guava库学习:学习Guava Cache(五)CacheLoader 中, 我们学习了CacheLoader抽象类,主要是其中的from方法,接收一个Function或Supplier,返回一个CacheLoader实 例,至此,我们已经了解了如何创建一个强大的缓存机制,接下来,我们想要收集缓存执行或使用后的一些统计信息,又该怎么做呢?现在开始本篇,Guava Cache CacheStats的学习.