Guava:LoadingCache缓存

1 LoadingCache

LoadingCache缓存通过load和reload进行数据初始化和刷新。
load为同步加载数据,初始化时使用。
reload异步更新数据,更新数据时使用。

2 Usage

package thirdparty;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListenableFutureTask;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

import java.util.concurrent.*;
import java.util.logging.Logger;

import static common.constant.DigitalConstant.*;
import static common.constant.DigitalConstant.TWO;

/**
 * LoadingCache测试样例.
 *
 * @author xindaqi
 * @date 2021-07-18 13:41
 */
public class GuavaLoadingCacheTest {

    private static final Logger logger = Logger.getLogger("GuavaLoadingCacheTest");

    /**
     * 普通线程池:ThreadPoolExecutor
     */
    private static ExecutorService threadPoolExecutorGenerate = new ThreadPoolExecutor(
            THREE,
            FIVE,
            THOUSAND_L,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(TWO),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.DiscardOldestPolicy());

    /**
     * Guava线程池
     */
    private static ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(threadPoolExecutorGenerate);

    /**
     * 建造LoadingCache,
     * 使用ThreadPoolExecutor线程池异步刷新数据
     */
    public static LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder()
            .refreshAfterWrite(10, TimeUnit.SECONDS)
            .expireAfterWrite(11, TimeUnit.SECONDS)
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String s) throws Exception {
                    return initializeCache();
                }

                @Override
                public ListenableFuture<String> reload(String key, String oldValue)
                        throws Exception {
                    ListenableFutureTask<String> task = ListenableFutureTask
                            .create(GuavaLoadingCacheTest::reloadCache);
                    logger.info("==============Reload");
                    threadPoolExecutorGenerate.submit(task);
                    return task;
                }
            });

    /**
     * 建造LoadingCache,
     * 使用Guava线程池异步刷新数据
     */
    public static LoadingCache<String, String> loadingCacheAnother = CacheBuilder.newBuilder()
            .refreshAfterWrite(10, TimeUnit.SECONDS)
            .expireAfterWrite(11, TimeUnit.SECONDS)
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String s) throws Exception {
                    return initializeCache();
                }

                @Override
                public ListenableFuture<String> reload(String key, String oldValue)
                        throws Exception {
                    return listeningExecutorService.submit(GuavaLoadingCacheTest::reloadCache);
                }
            });


    /**
     * 初始化Cache.
     *
     * @return 默认值
     */
    private static String initializeCache() {
        loadingCache.put("1", "xiaohua");
        loadingCache.put("2", "xiaolan");
        loadingCache.put("3", "xiaoxiao");
        logger.info("==========Load cache for initial==========");
        return "xiaoxin";
    }

    /**
     * 刷新Cache.
     *
     * @return 默认值
     */
    private static String reloadCache() {
        loadingCache.put("1", "xiaohuahua");
        loadingCache.put("2", "xiaolanlan");
        loadingCache.put("3", "xiaoxiaoxiao");
        logger.info("==========Reload cache for refresh==========");
        return "xiaoxinxin";
    }

    /**
     * 读取Cache,通过load初始化
     */
    private static void readCacheSelfInitialize() {
        String val1 = loadingCache.getIfPresent("1");
        logger.info("key1, value1:" + val1);

        String val2 = loadingCache.getIfPresent("2");
        logger.info("key2, value2:" + val2);

        try {
            String val1Get = loadingCache.get("1");
            logger.info("val1:" + val1Get);
        } catch(ExecutionException ee) {
            throw new RuntimeException(ee);
        }
    }

    /**
     * 读取Cache,通过reload刷新数据
     */
    private static void readCacheSelfRefreshTest() {
        String val1 = loadingCache.getIfPresent("1");
        logger.info("key1, value1:" + val1);

        String val2 = loadingCache.getIfPresent("2");
        logger.info("key2, value2:" + val2);

        try {
            String val1Get = loadingCache.get("1");
            logger.info("val1:" + val1Get);
            Thread.currentThread().sleep(2000);
        } catch(ExecutionException ee) {
            throw new RuntimeException(ee);
        } catch(InterruptedException ie) {
            throw new RuntimeException(ie);
        }
    }

    public static void main(String[] args) {

        readCacheSelfInitialize();
    }
}

  • 结果
七月 18, 2021 2:37:17 下午 thirdparty.GuavaLoadingCacheTest readCacheSelfInitialize
信息: key1, value1:null
七月 18, 2021 2:37:18 下午 thirdparty.GuavaLoadingCacheTest readCacheSelfInitialize
信息: key2, value2:null
七月 18, 2021 2:37:18 下午 thirdparty.GuavaLoadingCacheTest initializeCache
信息: Load cache for initial
七月 18, 2021 2:37:18 下午 thirdparty.GuavaLoadingCacheTest readCacheSelfInitialize
信息: val1:xiaoxin

3 读取LoadingCache数据

3.1 get

使用get方法获取LoadingCache数据时,没有获取到数据,调用load方法,load方法中可以初始化数据或者设置默认值。

  • get源码
public V get(K key) throws ExecutionException {
            return this.localCache.getOrLoad(key);
        }
  • getOrLoad源码
V getOrLoad(K key) throws ExecutionException {
        return this.get(key, this.defaultLoader);
    }

3.2 getIfPresent

使用getIfPresent方法,读取LoadingCache值:
(1)没有获取到值,LoadingCache返回null,通过判断返回值,进一步增加逻辑;
(2)获取到值,则直接使用。

  • getIfPresent源码
@NullableDecl
    public V getIfPresent(Object key) {
        int hash = this.hash(Preconditions.checkNotNull(key));
        V value = this.segmentFor(hash).get(key, hash);
        if (value == null) {
            this.globalStatsCounter.recordMisses(1);
        } else {
            this.globalStatsCounter.recordHits(1);
        }

        return value;
    }

4 小结

LoadingCache:

  • get获取值,没有查到数据,加载Load,获取默认值;
  • getIfPresent,没有查到值,直接返回null;
  • 刷新数据时,使用异步方法加载数据。

你可能感兴趣的:(#,Java,ABC,Guava,LoadingCache)