素材巴巴 > 程序开发 >

guava cache本地缓存的使用

程序开发 2023-09-10 14:43:50

1 本地缓存简单介绍

    本地缓存因为少了网络传输环节,所以读取速度比分布式缓存要快一些。HashMap、ConcurrentHashMap也能用作本地缓存,但是因为缺少必要的过期机制、容量限制、数据淘汰策略,不太合适。本文介绍guava cache本地缓存的用法,重点介绍下两种过期机制的区别:refreshAfterWrite和expireAfterWrite。

2 guava cache

guava cache的过期机制:

    两种过期策略在过期时都不会主动刷新缓存,只有下一次请求到来时才会刷新。

    示例:缓存过期时间设置为3s,启动3个线程,其中Thread-1、Thread-2并发获取缓存,每5s获取一次,Thread-3每秒查询一次缓存内容,缓存load时休息5s,模拟下load缓存的延时。

2.1 expireAfterWrite

package cache.guava;import com.google.common.cache.*;import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.concurrent.TimeUnit;/*** @Description guava本地缓存* @Author lilong* @Date 2019-03-14 19:55*/
 public class GuavaCacheService {private static LoadingCache localCache = CacheBuilder.newBuilder().maximumSize(5) // 缓存容量设为5,实际上只用到1个.expireAfterWrite(3, TimeUnit.SECONDS) // 一个线程load,其他线程阻塞等待.removalListener((removalNotification) -> { // 匿名内部类RemovalListenerSystem.out.println(Thread.currentThread().getName() + ":已移除");}).build(new CacheLoader() {@Overridepublic String load(String key) throws InterruptedException {System.out.println(Thread.currentThread().getName() + ":开始移除key..." + key);Thread.sleep(5000);LocalDateTime dateTime = LocalDateTime.now();String time = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);System.out.println(Thread.currentThread().getName() + ":移除成功key..." + key);return "key_" + key + "_" + time;}});public static void main(String[] args) {new Thread(new GetCache(), "Thread-1").start();new Thread(new GetCache(), "Thread-2").start();new Thread(() -> {while (true) {System.out.println(localCache.asMap());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}, "Thread-3").start();}static class GetCache implements Runnable {@Overridepublic void run() {while (true) {try {String val = localCache.get("a");System.out.println(Thread.currentThread().getName() + ":" + val);Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();}}}}
 }

运行看下打印,可以看到:

1)缓存存活时间3s,到期自动删除;

2)在获取缓存新值时,所有线程阻塞等待、直到有一个线程load成功;

3)获取到的新值时间戳比旧的延后10s,而不是load的延时5s,还没搞懂为什么

2.2 过期机制:refreshAfterWrite

把上面代码的expireAfterWrite换成refreshAfterWrite,打印日志,看到

1)缓存过期后不会清除;

2)在一个线程load阻塞住时,其他线程仍然能返回旧值,不会阻塞住。

​3)获取到的新值时间戳比旧的延后也是10s,而不是load的延时5s

3 解决分布式环境下本地缓存不一致问题

(1)kafka:

(2)zk:

    每台机器注册到zk上面去,类似dubbo服务注册的方式,所有机器都注册一个watch,一有变化全部通知,然后大家再去那一台机器取缓存。


标签:

素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。