java本地缓存 google guava

本文介绍Java本地缓存的概念与应用,探讨其在提高数据访问效率方面的作用,特别是在高并发场景下。深入分析Guava缓存库的配置与使用,包括并发控制、数据过期策略及缓存统计。

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

                                           java本地缓存 google guava

本地缓存产生背景:

本地缓存是指在我们本地的物理空间开辟出一片物理空间,专门用来存储我们需要向服务器端频繁需要的数据,

比如前端页面需要频繁的向后台访问某些数据,这时候我们每次都去数据库查找数据再返回给前台就会有很大的

开销。因为会涉及到磁盘I/O。但是如果我们把这些需要频繁访问的数据放在本地的物理空间,这样在访问的时候

就可以直接访问服务器缓存的数据。缓存这些数据的区域就是本地缓存。java的本地缓存存储在jvm的堆区的老年

代里,大小大约有几百兆。

本地缓存应用场景:

本地缓存虽然可以在本地缓存一些频繁申请的数据,但是毕竟是本地内存,大小还是需要一定限制的。我们一般

开发一些小的项目可以牺牲一定的本地内存当作缓存提高访问效率。开发一些比较大的项目本地缓存的数据量和

支持高并发就肯定不足了。这时候可能就需要分布式集群缓存,比如淘宝双十一的时候,难以估计马云开了多少

台服务器当作本地缓存和消息队列(接受客户的请求)。

本地缓存注意事项:

本地缓存虽然为我们提供了很大的方便,但是我们手动写一套本地缓存的组件还是需要注意很多问题的,数据结构

的选取,(一般用map结构),处理并发机制,本地缓存的过期,本地缓存在集群的同步问题,当内存不足的时候释放

本地内存,缓存的移除等。但是一般的第三方插件为我们处理好了这些问题,例如google guava

看看实现google guava的代码:

public static void main(String[] args) throws ExecutionException, InterruptedException{
        //缓存接口这里是LoadingCache,LoadingCache在缓存项不存在时可以自动加载缓存
        LoadingCache<Integer,Student> studentCache
                //CacheBuilder的构造函数是私有的,只能通过其静态方法newBuilder()来获得CacheBuilder的实例
                = CacheBuilder.newBuilder()
                //设置并发级别为8,并发级别是指可以同时写缓存的线程数
                .concurrencyLevel(8)
                //设置写缓存后8秒钟过期
                .expireAfterWrite(8, TimeUnit.SECONDS)
                //设置缓存容器的初始容量为10
                .initialCapacity(10)
                //设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
                .maximumSize(100)
                //设置要统计缓存的命中率
                .recordStats()
                //设置缓存的移除通知
                .removalListener(new RemovalListener<Object, Object>() {
                    @Override
                    public void onRemoval(RemovalNotification<Object, Object> notification) {
                        System.out.println(notification.getKey() + " was removed, cause is " + notification.getCause());
                    }
                })
                //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
                .build(
                        new CacheLoader<Integer, Student>() {
                            @Override
                            public Student load(Integer key) throws Exception {
                                System.out.println("load student " + key);
                                Student student = new Student();
                                student.setId(key);
                                student.setName("name " + key);
                                return student;
                            }
                        }
                );

        for (int i=0;i<20;i++) {
            //从缓存中得到数据,由于我们没有设置过缓存,所以需要通过CacheLoader加载缓存数据
            Student student = studentCache.get(1);
            System.out.println(student);
            //休眠1秒
            TimeUnit.SECONDS.sleep(1);
        }

        System.out.println("cache stats:");
        //最后打印缓存的命中率等情况
        System.out.println(studentCache.stats().toString());
    }
cache stats:
CacheStats{hitCount=17, missCount=3, loadSuccessCount=3, loadExceptionCount=0, totalLoadTime=1348802, evictionCount=2}

看看到在20此循环中命中次数是17次,未命中3次,这是因为我们设定缓存的过期时间是写入后的8秒,所以20秒内会

失效两次,另外第一次获取时缓存中也是没有值的,所以才会未命中3次,其他则命中。

上面的代码来自博文:使用google guava做内存缓存

### 使用Guava实现内存缓存 #### 创建项目并引入依赖 为了在Java中使用Guava的`Cache`功能,首先需要确保项目的构建文件包含了必要的依赖项。对于Maven项目,在`pom.xml`中添加如下依赖: ```xml <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version> </dependency> ``` #### 缓存接口定义 通常情况下会先定义一个通用的缓存接口来封装具体的缓存操作逻辑。 ```java public interface CacheService<K, V> { void put(K key, V value); V getIfPresent(Object key); } ``` #### 实现基于Guava的缓存服务 下面是一个实现了上述接口的具体例子,它利用了Guava提供的`LoadingCache`来进行自动加载和管理过期策略等功能。 ```java import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class GuavaCacheServiceImpl<K, V> implements CacheService<K, V> { private final LoadingCache<K, V> cache; public GuavaCacheServiceImpl(long expireAfterWriteDuration, TimeUnit timeUnit) { this.cache = CacheBuilder.newBuilder() .expireAfterWrite(expireAfterWriteDuration, timeUnit) .build(new CacheLoader<K, V>() { @Override public V load(K key) throws Exception { throw new ExecutionException(null, new UnsupportedOperationException("Key not found")); } }); } @Override public synchronized void put(K key, V value) { try { if (value != null && !cache.getIfPresent(key).equals(value)) { cache.put(key, value); } } catch (NullPointerException e) { cache.put(key, value); } } @Override public V getIfPresent(Object key) { return cache.getIfPresent(key); } } ``` 这段代码展示了如何配置最大容量、设置写入后失效时间以及自定义加载器等特性[^2]。 #### 测试案例 最后编写单元测试验证该缓存机制的工作情况。 ```java @Test void testGuavaCache() throws InterruptedException { CacheService<String, String> service = new GuavaCacheServiceImpl<>(5L, TimeUnit.SECONDS); // Put some data into the cache. service.put("key", "value"); // Retrieve cached item immediately after insertion. assertEquals(service.getIfPresent("key"), "value"); // Wait until entry expires and check again. Thread.sleep(6_000L); assertNull(service.getIfPresent("key")); } ``` 此示例说明了如何通过Guava库快速搭建起一套高效的本地缓存系统,并且可以根据实际需求调整参数以优化性能表现[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值