Guava Cache学习笔记

版权声明:博文主要参考网上资料,视频笔记,结合个人见解,仅供学习、交流使用,如有侵权,请联系博主删除。 https://blog.csdn.net/qq_40293674/article/details/87716074

Cache 相关参数说明

    1、大小:CacheBuilder.maxmumSize(long)
             CacheBuilder.weigher(Weigher)   
             CacheBuilder.maxmumWeigher(long)
    2、时间: expireAfterAccess(long,TimeUnit)
              expireAfterWrite(long,TimeUnit)
    3、引用: CacheBuilder.weakKeys()
              CacheBuilder.weakValues()
              CacheBuilder.softValues()
    4、删除: invalidate(key)
              invalidateAll(keys)
              invalidateAll()
    5、删除监听器: CacheBuilder.removalListener(RemovalListener)

 refresh(刷新) 机制:
    1、LoadingCache.refresh(key) 在生成新的value的时候,旧的value依然会使用
    2、CacheLoader.reload(K,V) 生成新的value过程中仍然允许使用旧的value
    3、CacheBuilder.refreshAfterWrite(long,TimeUnit)自动刷新cache

 

 /*
        Guava Cache 是一个全内存的本地缓存实现,它提供了线程安全的实现机制。(简单易用,性能好)
        Guava Cache 有两种创建方式:
            CacheLoader
            Callable
     */
 @Test
    public void testLoadingCache() throws ExecutionException {
        /*
            CacheLoader 的定义比较宽泛,是针对整个cache而言的,可以认为是  统一的根据key值load value的方法
         */
        LoadingCache<String,String> cacheBuilder = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                String strProValue = "hello " + key + "!";
                return strProValue;
            }
        });
        // cacheBuilder.apply("key");  --> 存值  : 会返回 重写的load方法里面的值
        System.out.println(cacheBuilder.apply("java1"));
        // cacheBuilder.get("key") -->  取值     get 方法可以实现,取值和存值, 如果 Get方法未取到值 会将其存入到cache中
        System.out.println(cacheBuilder.get("java"));
    }

    @Test
    public void testCallAbleCache() throws ExecutionException {
        /*
            Callable的方式比较灵活,允许在get的时候指定
         */
        Cache<String,String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();

        String  resultValue = cache.get("Java", new Callable<String>() {
            public String call() throws Exception {
                String strProValue = "hello" + "Java" + "!";
                return strProValue;
            }
        });
        // put 方法 存值, get 方法同理,有值取值  没值存值取值
        System.out.println(resultValue);
    }

从LoadingCache查询的方法是使用get(key)方法。这个方法会返回已经缓存的值,也会使用CacheLoader向缓存中增加新值。要注意的是,调用get()方法时,可能会抛出ExecutionException异常。

数据移除

Guava Cache中的数据移除分为主要移除和被动移除

被动移除,guava提供三种方式:

1、基于大小的移除(maxmumSize(long)):按照缓存的大小来移除数据,还有一个中按照权重来,但是不常使用

要注意的是 maxmumSize(long) 参数代表的是缓存的条数,其次并不是到了指定的size之后才会移除数据,而是在接近size大小的时候进行移除,另外如果一个键值对已经从缓存中被移除了,你再次请求访问的时候,如果cachebuild是使用cacheloader方式的,那依然还是会从cacheloader中再取一次值,如果这样还没有,就会抛出异常

2、基于时间移除

expireAfterAccess(long,TimeUnit) 某个键访问过了多少时间之后移除

expireAfterWrite(long,TimeUnit)某个键值对被创建或者被替换后多少时间后移除

3、基于引用移除

主要是基于java的垃圾回收机制,根据键或者值的引用关系决定移除

主动移除:

1、单独删除:Cache.invalidate(key)

2、批量删除:Cache.invalidateAll(keys)

3、移除所有:Cache.invalidateAll()

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

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

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

/**
     *  不需要延迟处理(泛型的方式封装)
     */
    public <K , V> LoadingCache<K , V> cached(CacheLoader<K , V> cacheLoader){
           
        LoadingCache<K, V> cache = CacheBuilder
                .newBuilder()
                .maximumSize(2)
                .weakKeys()
                .softValues()
                .refreshAfterWrite(120, TimeUnit.SECONDS)
                .expireAfterAccess(10, TimeUnit.SECONDS)
                .removalListener(new RemovalListener<K, V>() {
                    @Override
                    public void onRemoval(RemovalNotification<K, V> removalNotification) {
                        /*
                            通过CacheBuilder.removalListener(RmovalListener),可以声明一个监听器,以便缓存项被移除时
                            做一些额外操作。缓存项被移除时,RemovalListener会获取移除通知【RemovalNotification】,
                            其中 包含移除原因[RemovalCause]、键和值
                         */
                        System.out.println(removalNotification.getKey() + ",已被移除!");
                    }
                })
                .build(cacheLoader);
        return cache;
    }

    /**
     * 通过key获取value
     * 调用方式 commonCache.get(key); return string;
     */
    public LoadingCache<String,String> commonCache(final String key){
        LoadingCache<String, String> commonCache = cached(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                return "hello" + key + "!";
            }
        });
        return commonCache;
    }

    @Test
    public void testCache() throws ExecutionException {
        LoadingCache<String, String> cache = commonCache("java");
        System.out.println(cache.get("java"));

        cache.apply("python");
        System.out.println(cache.get("python"));

        cache.apply("c++");
        System.out.println(cache.get("c++"));
    }

    private static Cache<String, String> cacheFormCallable = null;

    /**
     * 对需要延迟处理的可以采用这个机制;(泛型的方式封装)
     * @param <K>
     * @param <V>
     * @return V
     * @throws Exception
     */
    public static <K, V> Cache<K, V> callableCached(){
        Cache<K, V> cache = CacheBuilder
                .newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build();
        return cache;
    }

    private String getCallableCache(final String userName){
        try{
            return cacheFormCallable.get(userName, new Callable<String>() {
                @Override
                public String call() throws Exception {
                    System.out.println(userName + "from db");
                    return "我是 "  + userName;
                }
            });
        } catch (ExecutionException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Callable 只有在缓存不存在时,才会调用,比如第二次调用getCallableCache(u1name) 直接返回缓存中的值
    @Test
    public void testCallableCache(){
        final String u1name = "java";
        final String u2name = "python";
        final String u3name = "c";
        cacheFormCallable = callableCached();
        System.out.println(getCallableCache(u1name));
        System.out.println(getCallableCache(u2name));
        System.out.println(getCallableCache(u3name));
        System.out.println(getCallableCache(u1name));
    }

猜你喜欢

转载自blog.csdn.net/qq_40293674/article/details/87716074