google的Guava Cache的使用(超详细)

1. 引入依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>27.0.1-jre</version>
</dependency>

2. 常用API

2.1 创建缓存

2.1.1 创建LoadingCache缓存

public class CacheTest {

    /**
     * 当进行查询时,若缓存中无数据,那么使用load方法进行动态加载。
     * 若load(key)方法返回"",那么缓存的value=""。
     */
    private static LoadingCache<String, String> cache1 = CacheBuilder.
            newBuilder().
            maximumSize(2).   //LRU缓存的最大个数
            removalListener((notification) -> System.out.println("移除掉的缓存值" +   //移除缓存的回调方法
            notification.getCause().name() + ":" +
            notification.getKey() + ":" +
            notification.getValue())).
            build(new CacheLoader<String, String>() {
                @Override
                public String load(String key) throws Exception {  //动态加载缓存
                    //从SQL或者NoSql 获取对象
                    if ("a".equals(key)) {
                        return "a-v";
                    }
                    return "";
                }
            });
    public static void main(String[] args) throws Exception {
        cache1();
    }


    private static void cache1() throws ExecutionException {

        System.out.println("a的缓存:" + cache1.get("a"));
        System.out.println("b的缓存:" + cache1.get("b"));

        cache1.put("c", "c");
        System.out.println("c的缓存:" + cache1.get("c"));
    }
}

执行结果:

a的缓存:a-v
b的缓存:
移除掉的缓存值SIZE:a:a-v
c的缓存:c

get("b"),因为cache1中并没有缓存,所以会调用CacheLoader的load方法加载缓存,注意CacheLoader的load方法不能返回null。但是返回""后,缓存存储的值如下图2.1-1所示,也是"’。

图2.1-1.png

2.1.2 创建Cache缓存

@Slf4j
public class CacheTest {
   
    private static Cache<String, String> cache2 = CacheBuilder.newBuilder().
            maximumSize(10).build();



    private static void cache2() throws Exception {


        System.out.println("cache2.getIfPresent(a):" + cache2.getIfPresent("a"));

        System.out.println("cache2.get(a) one:" + cache2.get("a", () -> {
            log.info("开始维护缓存,key:{}", "a");
            return "a-v";
        }));
        System.out.println("cache2.get(a) two:" + cache2.get("a", () -> {
            log.info("开始维护缓存,key:{}", "a");
            return "a-v";
        }));
        cache2.invalidate("a");
        System.out.println("invalidate后cache2.getIfPresent(a):" + cache2.getIfPresent("a"));
        //填充值
        cache2.put("b", "b");
        //删除值

        System.out.println("put后cache2.getIfPresent(b):" + cache2.getIfPresent("b"));
    }
}

执行结果:

cache2.getIfPresent(a):null
10:45:22.869 [main] INFO com.tellme.Test.jdk.CacheTest - 开始维护缓存,key:a
cache2.get(a) one:a-v
cache2.get(a) two:a-v
invalidate后cache2.getIfPresent(a):null
put后cache2.getIfPresent(b):b

Cache缓存,可以看做功能更加强大ConcurrentHashMap缓存。

2.2 创建缓存时的API

2.2.1 基于大小的数据移除

API方法作用
maximumSize最大的缓存条数,当达到最大条数,使用LRU移除。
maximumWeight&&weigher最大缓存“重量”,weigher为每一个缓存设置重量,当达到最大重量,使用LRU移除。

maximumWeight也不是基于对象真正占用内存,而是通过weigher为每一个缓存定义重量实现的。

    private static Cache<String, String> cache = CacheBuilder.newBuilder().
            maximumWeight(6).
            weigher((k, v) -> {
                if ("a".equals(k)) {
                    return 5;
                } else {
                    return 1;
                }
            }).
            build();

例如上述代码:key=“a”时,可能缓存的value占用内存比较大,故可以设置权重为5。其余缓存占用的内存比较小,可以设置权重为1。

注意:maximumWeightweigher需要搭配使用。

2.2.2 基于时间的数据移除

API方法作用
expireAfterAccess根据某个键值对最后一次访问之后多少时间后移除
expireAfterWrite据某个键值对被创建或值被替换后多少时间移除
refreshAfterWrite&&LoadingCacheLoadingCache下缓存写入后异步刷新

详细请见——guavaCache本地缓存失效方案expireAfterWrites和refreshAfterWrites

    private static Cache<String, String> cache = CacheBuilder.newBuilder().
            expireAfterAccess(2, TimeUnit.SECONDS).
            build();

2.2.3 基于引用的回收

引用类型作用
强引用常见普通对象引用,只要还有强引用指向一个对象,GC不能回收
软引用JVM认为内存不足,才会试图回收软引用指向的对象
弱引用一旦发生GC,就会回收弱引用指向的对象
虚引用虚引用不会决定对象的生命周期

JVM那点事-对象的自救计划(对象被设为null会被回收吗?)

guava也可以设置value的引用类型,来实现基于引用的回收。

@Slf4j
public class CacheTest {
    /**
     * 缓存大小
     */
    private static Cache<String, String> cache = CacheBuilder.newBuilder().
            weakValues().
            build();

    private static void cache() throws InterruptedException {
        cache.put("a",  new String("a"));
        //显式GC
        System.gc();
        System.out.println(cache.getIfPresent("a"));
    }
}

执行后果

null
API方法作用
softValues软引用,JVM认为内存不足,才会试图回收软引用指向的对象
weakValues弱引用,一旦发生GC,就会回收弱引用指向的对象

2.2.4 removalListener移除缓存时的监听

@Slf4j
public class CacheTest {
    /**
     * 缓存大小
     */
    private static Cache<String, String> cache = CacheBuilder.newBuilder().
            maximumSize(2).
            removalListener((notification) -> System.out.println("移除掉的缓存值" +   //移除缓存的回调方法
                    notification.getCause().name() + ":" +
                    notification.getKey() + ":" +
                    notification.getValue())).
            build();

    private static void cache() throws InterruptedException {
        cache.put("a", "a");
        cache.put("b", "b");
        cache.put("c", "c");
        System.out.println(cache.getIfPresent("a"));
    }
}

执行结果:

移除掉的缓存值SIZE:a:a
null

但是有点需要注意的是默认Removal Listener中的行为是和移除动作同步执行的,如果需要改成异步形式,可以考虑使用RemovalListeners.asynchronous(RemovalListener, Executor)

2.2.5 recordStats开启统计功能

@Slf4j
public class CacheTest {
    private static Cache<String, String> cache = CacheBuilder.newBuilder().
            maximumSize(2).
            recordStats().
            build();
    private static void cache() throws InterruptedException {
        cache.put("a", "a");
        cache.put("b", "b");
        cache.put("c", "c");
        System.out.println(cache.getIfPresent("b"));
        System.out.println(cache.getIfPresent("b"));
        System.out.println(cache.getIfPresent("c"));
        System.out.println(cache.getIfPresent("a"));

        CacheStats stats = cache.stats();
        System.out.println(JSON.toJSONString(stats));
    }
}

效果图:
image.png

2.3 操作缓存的API

2.3.1 显式移除缓存

API方式作用
invalidate(key)单独移除
invalidateAll(keys)批量移除
invalidateAll()移除所有

2.3.2 维护缓存的API

API方式作用
get()存在返回缓存值,不存在则调用Callable<? extends V> loader方法动态生成缓存值并存入缓存中
getIfPresent()若缓存存在则返回缓存,不存在则返回null
put(K key, V value)填充缓存
asMap()将缓存转换为Map

官方文档

guava Cache官方文档

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值