Guava缓存类LoadingCache的使用

本文详细介绍了Guava缓存的基本概念与实现原理,包括缓存的定义、过期策略、加载机制及性能考量。深入探讨了expireAfterWrite策略在缓存更新后的指定时间内使缓存失效的机制,以及其在高并发场景下的锁等待问题。同时,讲解了如何通过load()方法在缓存缺失时从数据库加载数据,并分析了recordStats()方法用于监控缓存命中率和加载平均时长的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 定义缓存

/**
     * 缓存
     * K:Pair<String, String> 集群名称,逻辑队列
     * V:String 物理队列
     */
    public LoadingCache<Pair<String, String>, String> clusterPhysicalQueueCache = CacheBuilder.newBuilder()
            .initialCapacity(initialCapacity)//初始容量
            .maximumSize(maximumSize)//最大容量
            .expireAfterWrite(expireAfterWrite,TimeUnit.SECONDS)//过期时间
            .recordStats()//开启统计
            .build(
                    new CacheLoader<Pair<String, String>, String>() {
                        @Override
                        public String load(Pair<String, String> key) throws Exception {
                            return getPhysicalFromDB(key);//查询数据库
                        }
                    }
            );

1.1 缓存过期清理方式

首先看一下三种基于时间的清理或刷新缓存数据的方式:

expireAfterAccess: 当缓存项在指定的时间段内没有被读或写就会被回收。

expireAfterWrite:当缓存项在指定的时间段内没有更新就会被回收。

refreshAfterWrite:当缓存项上一次更新操作之后的多久会被刷新。

 考虑到时效性,我们可以使用expireAfterWrite,使每次更新之后的指定时间让缓存失效,然后重新加载缓存。guava cache会严格限制只有1个加载操作,这样会很好地防止缓存失效的瞬间大量请求穿透到后端引起雪崩效应。

 然而,通过分析源码,guava cache在限制只有1个加载操作时进行加锁,其他请求必须阻塞等待这个加载操作完成;而且,在加载完成之后,其他请求的线程会逐一获得锁,去判断是否已被加载完成,每个线程必须轮流地走一个“”获得锁,获得值,释放锁“”的过程,这样性能会有一些损耗。这里由于我们计划本地缓存1秒,所以频繁的过期和加载,锁等待等过程会让性能有较大的损耗。

1.2 load()方法

什么时候被调用:从缓存获取不到数据,触发此方法,查询数据库,并将查询到的的数据添加到缓存里。
注意:不能return null,否则会报空指针异常。如果不需要进行查询数据库的操作,可以返回一个字符串"null"以防止它不报错。

1.3 recordStats()记录状态

clusterPhysicalQueueCache.stats().hitRate():获得命中率
clusterPhysicalQueueCache.stats().averageLoadPenalty():加载新的缓存的平均时长

1.4 build方法:自己定义load方法,加载获取缓存的方式

二. get和put方法获取缓存、添加缓存

/**获取物理队列
     * @param clusterQueue 集群,逻辑队列
     * @return
     * @throws ExecutionException
     */
    public String getPhysicalFromCache(Pair<String, String> clusterQueue) throws ExecutionException {
        String physicalName = clusterPhysicalQueueCache.get(clusterQueue);
        return physicalName;
    }

    /**加入缓存
     * @param clusterQueue 集群,逻辑队列
     * @param physical 物理队列
     */
    public void putCache(Pair<String, String> clusterQueue, String physical) {
        clusterPhysicalQueueCache.put(clusterQueue, physical);
    }

关于缓存的原理分析,可以看这篇https://blog.youkuaiyun.com/abc86319253/article/details/53020432

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值