本地缓存之Guava简单使用

文章目录

  • 使用场景
  • Guava Cache 的优势
  • Guava Cache使用
    • CacheLoader
    • Callable
    • 删除
      • 主动删除
      • 过期删除
      • 基于容量删除
      • 引用删除
    • 高级用法
    • 并发设置
    • 更新锁定
    • GuavaCache高级实战之疑难问题
      • GuavaCache会oom(内存溢出)吗
      • GuavaCache缓存到期就会立即清除吗
      • GuavaCache如何找出最久未使用的数据

使用场景

随着互联网用户越来越多,并发量、吞吐量越来越大

本地缓存的应用场景:

  1. 对性能有非常高的要求
  2. 不经常变化
  3. 占用内存不大
  4. 有访问整个集合的需求
  5. 数据允许不时时一致
    例如:拉勾网首页,由于首页经常被访问,可以将职位信息:java开发、大数据开发等放在本地缓存中。
    在这里插入图片描述

guava cache:高并发,不需要持久化
currentHashMap:高并发
Ehcached:持久化 二级缓存

Guava Cache 的优势

缓存机制淘汰算法可参考博文:本地缓存之LRU FIFO实现

  1. 缓存过期和淘汰机制:LRU
  2. 并发处理能力:类似CurrentHashMap,是线程安全的,采用了分段锁机制,将一个集合分成若干个人partiton ,每个Patrtiton一把锁,master多分区,利用segement作分区
  3. 更新锁定:GuavaCache可以在CacheLoader的load方法中加以控制,对同一个key,只让一个请求去读源并回填缓存,其他请求阻塞等待。.
  4. 集成数据源:而GuavaCache的get可以集成数据源,在从缓存中读取不到时可以从数据源中读取数据并回填缓
  5. 监控缓存加载/命中情况

Guava Cache使用

Cache创建:

方法作用
maximumSize容量
expireAfterWrite缓存项在给定时间内没有被写访问(创建或覆盖),则回收
recordStats缓存项在给定时间内没有被读/写访问,则回收
removalListener移除监听器
weakKeys弱引用存储键,当键没有其它(强或软)引用时,缓存项可以被垃圾回收
weakValues使用弱引用存储值。当值没有其它(强或软)引用时,缓存项可以被垃圾回收
concurrencyLevel并发操作

CacheLoader、Callable功能相同,都是在调用get方法时候,如果缓存不存在则指定数据源加载

CacheLoader

在创建缓存对象初始化时使用

模拟数据源

    public static HashMap<Integer, Integer> sourceMap = new HashMap<>();static {for (int i = 0; i < 10; i++){sourceMap.put(i, i);}}

使用demo

    public static void main(String[] args) throws ExecutionException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});for (int i = 0; i < 10; i++){cache.get(i);}System.out.println(cache.size());System.out.println(cache.asMap());}

在这里插入图片描述

Callable

调用get方法时当缓存数据不存在时候从数据源加载数据

使用demo:

    @Testpublic void call() throws ExecutionException {Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).build();Object value = cache.get(1, new Callable<Integer>() {@Overridepublic Integer call() throws Exception {return sourceMap.get(1);}});System.out.println(value);}

在这里插入图片描述

删除

主动删除

    @Testpublic void doDel() throws ExecutionException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).expireAfterAccess(3, TimeUnit.SECONDS).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});initCache(cache);//主动删除 key为1cache.invalidate(1);System.out.println("主动删除");displayCache(cache);// 批量删除cache.invalidateAll(Arrays.asList(1,2));System.out.println("批量删除");displayCache(cache);}

过期删除

expireAfterAccess:如果在一定时间内没被访问则数据过期

    @Testpublic void expireTimeDel() throws ExecutionException, InterruptedException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).expireAfterAccess(3, TimeUnit.SECONDS).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});initCache(cache);Thread.sleep(1000);cache.getIfPresent(1);Thread.sleep(2000);displayCache(cache);}

基于容量删除

    @Testpublic void sizeDel() throws ExecutionException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(1).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});Object v = cache.get(1);System.out.println(v);//自动删除1Object v2 = cache.get(2);displayCache(cache);}

引用删除

开启weakValues功能,采用弱引用,对引用不了解的可以看看,我的文章

    @Testpublic void referenceDel(){Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(3).weakValues().build();cache.put("1",new Object());//强制垃圾回收System.gc();System.out.println(cache.getIfPresent("1"));}

高级用法

并发设置

设置 concurrencyLevel 使得缓存支持并发的写入和读取

Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(3).concurrencyLevel(Runtime.getRuntime().availableProcessors()).build();

更新锁定

GuavaCache提供了一个refreshAfterWrite定时刷新数据的配置项,如果经过一定时间没有更新或覆盖,则会在下一次获取该值的时候,会在后台异步去刷新缓存

刷新时只有一个请求回源取数据,其他请求会阻塞(block)在一个固定时间段,如果在该时间段内没有获得新值则返回旧值。

    @Testpublic void refresh() throws InterruptedException, ExecutionException {LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder().maximumSize(3).concurrencyLevel(Runtime.getRuntime().availableProcessors()).refreshAfterWrite(3, TimeUnit.SECONDS).build(new CacheLoader<Integer, Integer>() {@Overridepublic Integer load(Integer key) throws Exception {return sourceMap.get(key);}});cache.get(1);System.out.println("第一次取值: " + cache.getIfPresent(1));sourceMap.put(1, 10);Thread.sleep(5000);System.out.println("第二次取值: " + cache.getIfPresent(1));}

应用场景:accesstoken token失效 从公网拿token 采用更新锁定在这里插入图片描述

GuavaCache高级实战之疑难问题

GuavaCache会oom(内存溢出)吗

会,当我们设置缓存永不过期(或者很长),缓存的对象不限个数(或者很大)时,比如:

Cache<String, String> cache = CacheBuilder.newBuilder()
.expireAfterWrite(100000, TimeUnit.SECONDS)
.build();

解决方案:缓存时间设置相对小些,使用弱引用方式存储对象

GuavaCache缓存到期就会立即清除吗

不是的,GuavaCache是在每次进行缓存操作的时候,如get()或者put()的时候,判断缓存是否过期。

一个如果一个对象放入缓存以后,不在有任何缓存操作(包括对缓存其他key的操作),那么该缓存不
会主动过期的。

GuavaCache如何找出最久未使用的数据

用accessQueue,这个队列是按照LRU的顺序放的缓存对象(ReferenceEntry)的,会把访问过的对象放在队列的最后。

并且可以很方便的更新和删除链表中的节点,因为每次访问的时候都可能需要更新链表,放入到链表的尾部。

这样,每次从access中拿出的头结点就是最久未使用的。

对应的writeQueue用来保存最久未更新的缓存队列,实现方式和accessQueue一样。

其他比较好的文章推荐:

中文教程

Guava总结好的博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/508847.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

本地缓存之LIFO、LRU、FIFO、LFU实现

文章目录LIFO算法实现LRU算法算法核心实现FIFO算法LFU算法LIFO算法 后进先出,利用栈实现 实现 Testpublic void stackDemo(){Stack<Integer> stack new Stack<>();for (int i 1; i < 4; i){stack.add(i);}ArrayList<Integer> list new ArrayList<…

java中强引用、弱引用、软引用、虚引用学习

文章目录强引用弱引用软引用虚引用将引用之前首先让我们一起回顾一下java对象的生命周期强引用 在实际开发场景中&#xff0c;我们一般使用的都是强引用&#xff0c;只要强引用存在&#xff0c;垃圾回收即使OOM也不会回收&#xff0c;知道强引用释放以后&#xff0c;对象才会被…

mysql left join、right join、inner join、union、union all使用以及图解

左外连接&#xff1a;left join sql语法&#xff1a;LEFT JOIN LEFT OUTER JOIN 首先需要创建两张表做测试&#xff0c;表数据如下所示 table 1 表&#xff1a; table2 表&#xff1a; 查询sql&#xff1a; select * from table1 a LEFT JOIN table2 b on a.idb.id 总结&a…

java 将海外时区转换为北京时区

//默认为上海时区TimeZone tz TimeZone.getDefault();//北京时区tz TimeZone.getTimeZone("GMT8");Date date new Date(System.currentTimeMillis());// 获取默认的DateFormat&#xff0c;用于格式化DateSimpleDateFormat simpleDateFormat new SimpleDateFormat…

Java规则引擎-MVEL表达式解析器

MVEL是一个功能强大的基于Java应用程序的表达式语言。 目前最新的版本是2.0&#xff0c;具有以下特性&#xff1a; (1). 动态JIT优化器。当负载超过一个确保代码产生的阈值时&#xff0c;选择性地产生字 节代码,这大大减少了内存的使用量。新的静态类型检查和属性支持&#xff…

第十八章 Swing程序设计

Swing用于开发桌面窗体程序&#xff0c;是JDK的第二代GUI框架&#xff0c;其功能比JDK第一代GUI框架AWT更为强大、性能更加优良。但因为Swing技术推出时间太早&#xff0c;其性能、开发效率等不及一些其他流行技术&#xff0c;所以目前市场上大多数桌面窗体程序都不是由Java开发…

ConcurrentLinkedQueue常用方法

Testpublic void queuedemo(){ConcurrentLinkedQueue<Integer> queue new ConcurrentLinkedQueue();for (int i 0; i < 5; i){queue.add(i);}//获取元素 不移除头结点for (int i 0; i < 3; i){System.out.println("peek: " queue.peek());}//返回在此…

redis stream学习总结

文章目录streamStream基本概念消息id消息内容增删查改消息生产添加消息 xadd查看消息长度 xlen限制stream最大长度1.xadd 中添加**maxlen**:2.xtrim查询消息 xrange正向排序&#xff1a;消费id从小到大排反向查询&#xff1a;消费id从大到小排删除消息消息消费独立消费 xread消…

jedis StreamEntryID参数解释

//$ 在给定Stream中已经包含的最大ID&#xff0c;在xread、xcreategroup中标识消费着只能消费最新消息 StreamEntryID.LAST_ENTRY; “>” 在消费者组的上下文中使用&#xff0c;在xread、xreadgroup总标识消费未消费过的消息 StreamEntryID.UNRECEIVED_ENTRY; 如果传入的为…

RabbitMQ TTL、死信队列在订单支付场景的应用

基于RabbitMQ的TTL以及死信队列&#xff0c;使用SpringBoot实现延迟付款&#xff0c;手动补偿操作。 1、用户下单后展示等待付款页面 2、在页面上点击付款的按钮&#xff0c;如果不超时&#xff0c;则跳转到付款成功页面 3、如果超时&#xff0c;则跳转到用户历史账单中查看…

阿里巴巴Java开发手册-使用JDK8的Opional类来防止出现NPE问题

/*** https://www.baeldung.com/java-optional*/Testpublic void optionalTest(){Peo peo new Peo("weijie", 18);/*** of、ofNullable*///of 判断peo是否为空&#xff0c;如果不为空程序继续执行Optional<Peo> _of Optional.of(peo);//程序直接抛出NullExce…

阿里巴巴Java开发手册-finally块必须对资源对象、流对象进行关闭操作,如果有异常也要做try-cach操作

对于JDK7及以上版本&#xff0c;可以使用try-with-resources方式 使用方式&#xff1a; /*** https://www.cnblogs.com/itZhy/p/7636615.html* 其实这种方式只是语法糖&#xff0c;反编译以后还是tryCacheThrowTest()中的代码* https://www.cnblogs.com/langtianya/p/5139465.h…

阿里巴巴Java开发手册-日志规约

1.【强制】 应用中不可直接使用日志系统(Log4j、Logback)中的API&#xff0c;而应依赖使用的SLF4j中的API。使用门面模式的日志框架吗&#xff0c;有利于维护和各个类的日志处理方式统一。 import org.slf4j.Logger;import org.slf4j.LoggerFactory;Logger logger LoggerFacto…

Java 回调 (Callback) 接口学习使用

文章目录Java 回调 (Callback) 接口学习使用1.什么是回调(Callback)&#xff1f;2.Java代码示例2.直接调用3.接口调用4.Lambda表达式推荐看我的InfoQ地址&#xff0c;界面排版更简洁Java 回调 (Callback) 接口学习使用 1.什么是回调(Callback)&#xff1f; 回调函数&#xff0…

常用的限流算法学习

常用的限流算法有漏桶算法和令牌桶算法&#xff0c;guava的RateLimiter使用的是令牌桶算法&#xff0c;也就是以固定的频率向桶中放入令牌&#xff0c;例如一秒钟10枚令牌&#xff0c;实际业务在每次响应请求之前都从桶中获取令牌&#xff0c;只有取到令牌的请求才会被成功响应…

基于rocketMq秒杀系统demo

基于RocketMQ设计秒杀。 要求&#xff1a; 1. 秒杀商品LagouPhone&#xff0c;数量100个。 2. 秒杀商品不能超卖。 3. 抢购链接隐藏 4. NginxRedisRocketMQTomcatMySQL 实现 接口说明&#xff1a;https://www.liuchengtu.com/swdt/#R9f978d0d00ef9be99f0…

常见压缩算法学习

文章目录无损压缩算法理论基础信息熵熵编码字典编码综合通用无损压缩算法相关常见名词说明java对几种常见算法实现Snappydeflate算法Gzip算法huffman算法Lz4算法Lzo算法使用方式无损压缩算法理论基础 信息熵 信息熵是一个数学上颇为抽象的概念&#xff0c;在这里不妨把信息熵理…

java中钩子方法 addShutdownHook 学习使用

钩子作用&#xff1a; 在线上Java程序中经常遇到进程程挂掉&#xff0c;一些状态没有正确的保存下来&#xff0c;这时候就需要在JVM关掉的时候执行一些清理现场的代码。Java中得ShutdownHook提供了比较好的方案。 JDK在1.3之后提供了Java Runtime.addShutdownHook(Thread hook)…

基于Curator实现dubbo服务自动注册发现

文章目录概念基于ServiceDiscovery实现服务自动注册和发现Service:服务基本信息InstanceDetails:封装实例用过来保存到zk中ServiceProvider&#xff1a;服务提供者ServiceConsumer&#xff1a;服务消费者运行基于ServiceDiscovery、ServiceCache实现服务自动注册和发现Registry…

jdk、cglib动态代理代码示例

文章目录jdk动态代理实现步骤代码示例新建一个接口新建一个接口的实现类新建一个代理类调用测试cglib动态代理实现实现步骤创建一个实现类新建一个代理类调用测试jdk动态代理 实现步骤 新建一个接口新建一个接口的实现类新建一个代理类&#xff0c;实现InvocationHandler接口…