右耳菌-邓小白的Java架构师的修炼之路

Guava Cache

2022-06-09  本文已影响0人  右耳菌

Google Guava Cache是一种非常优秀本地缓存解决方案,提供了基于容量,时间和引用的缓存回收方式。

Guava Cache与ConcurrentMap很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除。Guava Cache为了限制内存占用,通常都设定为自动回收元素。

maven 引用

    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>31.1-jre</version>
        </dependency>
    </dependencies>

适用场景

Tips: guava cache是运行在JVM的本地缓存,并不能把数据存放到外部服务器上。如果有这样的要求,因该尝试MemcachedRedis这类分布式缓存。


Guava Cache 加载

package cn.lazyfennec.guava;

import com.google.common.cache.*;

import java.util.concurrent.TimeUnit;

/**
 * 加载方式1:CacheLoader
 * 1.设置缓存容量
 * 2.设置超时时间
 * 3.提供移除监听器
 * 4.提供缓存加载器
 * 5.构建缓存
 *
 * @Author: Neco
 * @Description: 加载方式1:CacheLoader
 * @Date: create in 2022/6/9 16:22
 */
public class GuavaCacheDemo1 {

    public static void main(String[] args) {
        // CacheLoader 初始化
        CacheLoader<String, Object> cacheLoader = new CacheLoader<String, Object>() {
            @Override
            // load方法的作用是在通过get方法从LoadingCache获取不到值时去加载该值并放入缓存。
            public String load(String key) throws Exception {
                // 模拟加载值的过程
                Thread.sleep(1000);
                // 假设某个key是非法访问的
                if ("err".equals(key)) {
                    return null;
                }
                return key + "'s value";
            }
        };

        // 移出监听器配置
        RemovalListener<String, Object> removalListener = new RemovalListener<String, Object>() {
            // 移出时触发的事件
            public void onRemoval(RemovalNotification<String, Object> removal) {
                System.out.println("[" + removal.getKey() + ":" + removal.getValue() + "] is evicted!");
            }
        };

        //
        LoadingCache<String, Object> caches = CacheBuilder.newBuilder()
                // 设置容量大小
                .maximumSize(5)
                // 设置超时时间
                .expireAfterWrite(10, TimeUnit.SECONDS)
                .expireAfterAccess(10, TimeUnit.SECONDS)
                // 移出监听器
                .removalListener(removalListener)
                // 加载器配置
                .build(cacheLoader);

        // 由于缓存的容易只设置了5个,存入10个就会由guava基于容量回收掉5个
        for (int i = 0; i < 10; i++) {
            String key = "key" + i;
            String value = "value" + i;
            caches.put(key, value);
            System.out.println("[" + key + ":" + value + "] is put into cache!");
        }

        // 如果存在就获取
        System.out.println(caches.getIfPresent("key6"));

        try {
            caches.get("err");
        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println("不存在key,会报错");
        }
    }

}
[key0:value0] is put into cache!
[key1:value1] is put into cache!
[key2:value2] is put into cache!
[key3:value3] is put into cache!
[key4:value4] is put into cache!
[key0:value0] is evicted!
[key5:value5] is put into cache!
[key1:value1] is evicted!
[key6:value6] is put into cache!
[key2:value2] is evicted!
[key7:value7] is put into cache!
[key3:value3] is evicted!
[key8:value8] is put into cache!
[key4:value4] is evicted!
[key9:value9] is put into cache!
value6
不存在key,会报错

package cn.lazyfennec.guava;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

/**
 * 加载方式2:Callable
 * 所有类型的Guava Cache,不管有没有自动加载功能,都支持get(K, Callable<V>)方法。
 * 这个方法返回缓存中相应的值,或者用给定的Callable运算并把结果加入到缓存中。
 * 在整个加载方法完成前,缓存项相关的可观察状态都不会更改。
 * 这个方法简便地实现了模式"如果有缓存则返回;否则运算、缓存、然后返回"。
 *
 * @Author: Neco
 * @Description: 加载方式2:Callable
 * @Date: create in 2022/6/9 17:04
 */
public class GuavaCacheDemo2 {
    // 构建容量为3的缓存对象
    static Cache<String, String> caches = CacheBuilder.newBuilder()
            .maximumSize(3)
            .build();

    public static void main(String[] args) {
        caches.put("1234", "我是存在的");

        // 如果存在就获取,不存在返回null
        System.out.println(caches.getIfPresent("key6"));

        try {
            // 获取key为123的缓存数据,如果有就返回,没有就返回call方法的返回值
            System.out.println(caches.get("123", new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return "运算、缓存、然后返回";
                }
            }));

            // 获取key为1234的缓存数据,如果有就返回,没有就返回call方法的返回值。注意这里key是存在的
            System.out.println(caches.get("1234", new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return "我是打酱油的";
                }
            }));
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
null
运算、缓存、然后返回
我是存在的

Guaca Cache 缓存回收

                // 设置缓存容量
                .maximumSize(5)
                // 设置超时时间
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .expireAfterAccess(10, TimeUnit.MINUTES)
            // 当值没有其它(强或软)引用时,缓存项可以被垃圾回收
            .weakValues()

Guaca Cache 显式清除

任何时候都可以显式地清除缓存项,而不是等待被回收:

package cn.lazyfennec.guava;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/6/9 17:14
 */
public class GuavaCacheDemo3 {
    static Cache<String, Object> testCache = CacheBuilder.newBuilder()
            // 当值没有其它(强或软)引用时,缓存项可以被垃圾回收
            .weakValues()
            // 开启Guava Cache的统计功能
            .recordStats()
            .build();

    public static void main(String[] args) {
        Object obj1 = new Object();

        testCache.put("1234", obj1);

        obj1 = new String("123");

        // 主动gc
        System.gc();

        System.out.println(testCache.getIfPresent("1234"));

        /*
        stats()方法会返回CacheS tats 对象以提供如下统计信息:
            hitRate():缓存命中率;
            averageLoadPenalty():加载新值的平均时间,单位为纳秒;
            evictionCount():缓存项被回收的总数,不包括显式清除。
         */
        System.out.println(testCache.stats());

    }
}
null
CacheStats{hitCount=0, missCount=1, loadSuccessCount=0, loadExceptionCount=0, totalLoadTime=0, evictionCount=0}

Guava Cache 统计

  • hitRate():缓存命中率
  • averageLoadPenalty():加载新值的平均时间,单位为纳秒
  • evictionCount():缓存项被回收的总数,不包括显示清除

如果觉得有收获就点个赞吧,更多知识,请点击关注查看我的主页信息哦~

上一篇 下一篇

猜你喜欢

热点阅读