Guava缓存解读

Mar 11, 2017


导读

教程的话大家可以参考Guava官方文档英文版

  • Guava在公司应用非常普遍了,虽然有些场景还是会使用apache-common工具包,但是相比而言Guava扩展性更强,功能也更强大
  • 并且Guava中的代码很早就体现出函数式编程的方式,通过优雅的函数式声明接口,使用匿名类,内部类相互结合扩展使用
  • 以上仅仅代表个人理解,这篇博文主要是谈一下我在学习Guava-Cache的一些记录
  • 这里提到的Cache属于本地缓存,属于jvm级别缓存

Guava-Cache

为什么需要Guava-Cache?

为什么Google专门写一个cache工具呢?

一般情况下使用HashMap做为缓存容器,在并发数比较高的情况下使用juc.ConcurrentMap

Guava-Cache内部使用ConcurrentMap作为缓存容器,当然只是实现ConcurrentMap接口,对此做了扩展

我觉得最重要的一点就是简化开发工作量,提升开发效率

但是相比而言Guava对此做了一系列的封装扩展,使得定制性更强

比如我们如果使用Map,必须显示移除数据,Guava可以设定过期策略

Guava允许我们设定不同的参数来控制cache

设定监听器去监听当缓存被移除后触发自定义逻辑

Key,Value可是设定不同的引用策略(强引用,软引用,虚引用)

对于软引用,虚引用的介绍与其在缓存中的应用请参考:Java-软引用、弱引用、虚引用

创建方式

两种创建方式:

    1. 使用CacheLoader方式,统一的在get(String key)构造指定逻辑的value,当key是第一次加载,put则不受影响
    1. 使用CallBack回调方式,没有统一的构造指定逻辑value,在每一次get(String key)可以自定义value构造逻辑,若key之前存在,则直接返回之前的value

简单使用:

public class GuavaCacheTest {

    private static final Logger logger = LoggerFactory.getLogger(GuavaCacheTest.class);

    private static final CacheBuilder<String, String> builder = CacheBuilder.newBuilder().maximumSize(1000)
            .expireAfterWrite(10, TimeUnit.SECONDS).removalListener(new RemovalListener<String, String>() {
                @Override
                public void onRemoval(RemovalNotification<String, String> notification) {
                    // process
                    logger.info("remove : " + notification.getKey());
                }
            });

    // 使用CacheLoader方式
    private static final LoadingCache<String, String> cacheBuilder = builder.build(new CacheLoader<String, String>() {
                @Override
                public String load(String key) throws Exception {
                    return "hello " + key + "!";
                }
            });

    // 使用CallBack方式
    private static final Cache<String, String> cache = builder.build();

    public static void main(String[] args) throws ExecutionException {
        //CacheLoader方式
        logger.trace(cacheBuilder.get("dynamo"));
        cacheBuilder.put("test", "test1");
        logger.trace(cacheBuilder.get("test"));
        //CallBack方式
        final String name = "dynamo";
        cache.put("test", "test1");
        logger.trace(cache.get(name, new Callable<String>() {
            @Override public String call() throws Exception {
                return "hello " + name + "!";
            }
        }));
        logger.trace(cache.get(name, new Callable<String>() {
            @Override public String call() throws Exception {
               return "second hello " + name + "!";
            }
        }));
        logger.trace(cache.getIfPresent("test"));
        //remove
        cacheBuilder.invalidate("test");
        cache.invalidate("test");
    }
}

源码分析

Guava-Cache存储结构图

guava-cache

待更新