Java内存缓存工具Guava LoadingCache使用解析

这篇文章主要介绍了Java内存缓存工具Guava LoadingCache使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

一、Guava介绍

Guava是Google guava中的一个内存缓存模块,用于将数据缓存到JVM内存中。实际项目开发中经常将一些公共或者常用的数据缓存起来方便快速访问。

Guava Cache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。如果不符合需求,可以选择Memcached、Redis等工具。

二、代码示例

1. POM引入

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>28.1-jre</version>
</dependency>

2. 封装工具类

package com.soyoung.ad.engine.util;

import com.google.common.cache.*;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 功能描述
 *
 * @author 马振全 2020/1/13 16:18
 */
@Slf4j
public class CacheManager {

  /** 缓存项最大数量 */
  private static final long GUAVA_CACHE_SIZE = 100000;

  /** 缓存时间:天 */
  private static final long GUAVA_CACHE_DAY = 10;

  /** 缓存操作对象 */
  private static LoadingCache<Long, String> GLOBAL_CACHE = null;

  static {
    try {
      GLOBAL_CACHE = loadCache(new CacheLoader<Long, String>() {
        @Override
        public String load(Long key) throws Exception {
          // 处理缓存键不存在缓存值时的处理逻辑
          return "";
        }
      });
    } catch (Exception e) {
      log.error("初始化Guava Cache出错", e);
    }
  }

  /**
   * 全局缓存设置
   *
   * 缓存项最大数量:100000
   * 缓存有效时间(天):10
   *
   *
   * @param cacheLoader
   * @return
   * @throws Exception
   */
  private static LoadingCache<Long, String> loadCache(CacheLoader<Long, String> cacheLoader) throws Exception {
    LoadingCache<Long, String> cache = CacheBuilder.newBuilder()
        //缓存池大小,在缓存项接近该大小时, Guava开始回收旧的缓存项
        .maximumSize(GUAVA_CACHE_SIZE)
        //设置时间对象没有被读/写访问则对象从内存中删除(在另外的线程里面不定期维护)
        .expireAfterAccess(GUAVA_CACHE_DAY, TimeUnit.DAYS)
        // 设置缓存在写入之后 设定时间 后失效
        .expireAfterWrite(GUAVA_CACHE_DAY, TimeUnit.DAYS)
        //移除监听器,缓存项被移除时会触发
        .removalListener(new RemovalListener<Long, String>() {
          @Override
          public void onRemoval(RemovalNotification<Long, String> rn) {
            //逻辑操作
          }
        })
        //开启Guava Cache的统计功能
        .recordStats()
        .build(cacheLoader);
    return cache;
  }

  /**
   * 设置缓存值
   * 注: 若已有该key值,则会先移除(会触发removalListener移除监听器),再添加
   *
   * @param key
   * @param value
   */
  public static void put(Long key, String value) {
    try {
      GLOBAL_CACHE.put(key, value);
    } catch (Exception e) {
      log.error("设置缓存值出错", e);
    }
  }

  /**
   * 批量设置缓存值
   *
   * @param map
   */
  public static void putAll(Map<? extends Long, ? extends String> map) {
    try {
      GLOBAL_CACHE.putAll(map);
    } catch (Exception e) {
      log.error("批量设置缓存值出错", e);
    }
  }

  /**
   * 获取缓存值
   * 注:如果键不存在值,将调用CacheLoader的load方法加载新值到该键中
   *
   * @param key
   * @return
   */
  public static String get(Long key) {
    String token = "";
    try {
      token = GLOBAL_CACHE.get(key);
    } catch (Exception e) {
      log.error("获取缓存值出错", e);
    }
    return token;
  }

  /**
   * 移除缓存
   *
   * @param key
   */
  public static void remove(Long key) {
    try {
      GLOBAL_CACHE.invalidate(key);
    } catch (Exception e) {
      log.error("移除缓存出错", e);
    }
  }

  /**
   * 批量移除缓存
   *
   * @param keys
   */
  public static void removeAll(Iterable<Long> keys) {
    try {
      GLOBAL_CACHE.invalidateAll(keys);
    } catch (Exception e) {
      log.error("批量移除缓存出错", e);
    }
  }

  /**
   * 清空所有缓存
   */
  public static void removeAll() {
    try {
      GLOBAL_CACHE.invalidateAll();
    } catch (Exception e) {
      log.error("清空所有缓存出错", e);
    }
  }

  /**
   * 获取缓存项数量
   *
   * @return
   */
  public static long size() {
    long size = 0;
    try {
      size = GLOBAL_CACHE.size();
    } catch (Exception e) {
      log.error("获取缓存项数量出错", e);
    }
    return size;
  }
}

三、使用总结

1. 移除机制

guava做cache时候数据的移除分为被动移除和主动移除两种。

被动移除分为三种:

基于大小的移除:数量达到指定大小,会把不常用的键值移除

基于时间的移除:expireAfterAccess(long, TimeUnit) 根据某个键值对最后一次访问之后多少时间后移除
        expireAfterWrite(long, TimeUnit) 根据某个键值对被创建或值被替换后多少时间移除

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

主动移除分为三种:1).单独移除:Cache.invalidate(key)

         2).批量移除:Cache.invalidateAll(keys)

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

如果配置了移除监听器RemovalListener,则在所有移除的动作时会同步执行该listener下的逻辑。

如需改成异步,使用:RemovalListeners.asynchronous(RemovalListener, Executor)

2. 遇到的问题

在put操作之前,如果已经有该键值,会先触发removalListener移除监听器,再添加
配置了expireAfterAccess和expireAfterWrite,但在指定时间后没有被移除。

解决方案:CacheBuilder构建的缓存不会在特定时间自动执行清理和回收工作,也不会在某个缓存项过期后马上清理,它不会启动一个线程来进行缓存维护,因为a)线程相对较重,b)某些环境限制线程的创建。它会在写操作时顺带做少量的维护工作,或者偶尔在读操作时做。当然,也可以创建自己的维护线程,以固定的时间间隔调用Cache.cleanUp()。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • JavaWeb禁止浏览器缓存当前Web页面的方法

    所谓浏览器缓存,是指当第一次访问网页时,浏览器会将这些网页缓存到本地,当下一次再访问这些被缓存的网页时,浏览器就会直接从本地读取这些网页的内容,而无需再从网络上获取. 虽然浏览器提供的缓存功能可以有效地提高网页的装载速度,但对于某些需要实时更新的网页,这种缓存机制就会影响网页的正常显示.幸好在HTTP响应消息头中提供了三个字段可以关闭客户端浏览器的缓存功能.下面三条语句分别使用这三个字段来关闭浏览器的缓存: response.setDateHeader("Expires", 0); r

  • 一次 Java 内存泄漏的排查解决过程详解

    由来 前些日子小组内安排值班,轮流看顾我们的服务,主要做一些报警邮件处理.Bug 排查.运营 issue 处理的事.工作日还好,无论干什么都要上班的,若是轮到周末,那这一天算是毁了. 不知道是公司网络广了就这样还是网络运维组不给力,网络总有问题,不是这边交换机脱网了就是那边路由器坏了,还偶发地各种超时,而我们灵敏地服务探测服务总能准确地抓住偶现的小问题,给美好的工作加点料.好几次值班组的小伙伴们一起吐槽,商量着怎么避过服务保活机制,偷偷停了探测服务而不让人发现(虽然也并不敢). 前些天我就在周末

  • 详细介绍高性能Java缓存库Caffeine

    1.介绍 在本文中,我们来看看Caffeine- 一个高性能的 Java 缓存库. 缓存和 Map 之间的一个根本区别在于缓存可以回收存储的 item. 回收策略为在指定时间删除哪些对象.此策略直接影响缓存的命中率 - 缓存库的一个重要特征. Caffeine 因使用 Window TinyLfu 回收策略,提供了一个近乎最佳的命中率. 2.依赖 我们需要在 pom.xml 中添加 caffeine 依赖: <dependency> <groupId>com.github.ben-

  • 在Java中使用redisTemplate操作缓存的方法示例

    背景 在最近的项目中,有一个需求是对一个很大的数据库进行查询,数据量大概在几千万条.但同时对查询速度的要求也比较高. 这个数据库之前在没有使用Presto的情况下,使用的是Hive,使用Hive进行一个简单的查询,速度可能在几分钟.当然几分钟也并不完全是跑SQL的时间,这里面包含发请求,查询数据并且返回数据的时间的总和.但是即使这样,这样的速度明显不能满足交互式的查询需求. 我们的下一个解决方案就是Presto,在使用了Presto之后,查询速度降到了秒级.但是对于一个前端查询界面的交互式查询来

  • java中对Redis的缓存进行操作的示例代码

    Redis 是一个NoSQL数据库,也是一个高性能的key-value数据库.一般我们在做Java项目的时候,通常会了加快查询效率,减少和数据库的连接次数,我们都会在代码中加入缓存功能.Redis的高效缓存功能给我们解决了难题.下面我主要讲讲在Java项目中怎么去连接Redis服务器以及需要注意的事项. 1.导入必须的Jar包 使用Java操作Redis需要两个必须的Jar包:jedis-2.5.1.jar 和  commons-pool2-2.0.jar .每个版本可以不一样,根据你自己下载的

  • javaWeb中使用Redis缓存实例解析

    直接进入主题: 一:serviceImpl定义: @Service public class JedisClientSingleService implements JedisClient { @Autowired private JedisPool jedisPool; @Override public String get(String key) { Jedis jedis = jedisPool.getResource(); String string = jedis.get(key);

  • Java Ehcache缓存框架入门级使用实例

    前言 JAVA缓存实现方案有很多,最基本的自己使用Map去构建缓存,或者使用memcached或Redis,但是上述两种缓存框架都要搭建服务器,而Map自行构建的缓存可能没有很高的使用效率,那么我们可以尝试一下使用Ehcache缓存框架. Ehcache主要基于内存缓存,磁盘缓存为辅的,使用起来方便.下面介绍如何在项目中使用Ehcache 入门使用教程 1.maven引用 <dependency> <groupId>net.sf.ehcache</groupId> &l

  • Java编程guava RateLimiter实例解析

    本文主要研究的是Java编程guava RateLimiter的相关内容,具体如下. 令牌桶算法(token bucket algorithm) 场景1 在流量监管中的应用 约定访问速率(CAR)是流量监管常用技术之一,可以应用在端口进和出方向,一般应用在入方向,它的监管原理如图1所示. a. 按特定的速率向令牌桶投放令牌 b. 根据预设的匹配规则先对报文进行分类,不符合匹配规则的报文不需要经过令牌桶的处理,直接发送: c. 符合匹配规则的报文,则需要令牌桶进行处理.当桶中有足够的令牌则报文可以

  • java如何获取系统CPU、内存占用

    说明:获取的数据是操作系统整体的资源占用情况,不是当前 java进程占用的资源 1. 获取系统CPU占用情况 : import java.lang.management.ManagementFactory; import com.sun.management.OperatingSystemMXBean; private static OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperati

  • Java内存缓存工具Guava LoadingCache使用解析

    这篇文章主要介绍了Java内存缓存工具Guava LoadingCache使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.Guava介绍 Guava是Google guava中的一个内存缓存模块,用于将数据缓存到JVM内存中.实际项目开发中经常将一些公共或者常用的数据缓存起来方便快速访问. Guava Cache是单个应用运行时的本地缓存.它不把数据存放到文件或外部服务器.如果不符合需求,可以选择Memcached.Redis等工具

  • Java本地缓存工具之LoadingCache的使用详解

    目录 前言 环境依赖 代码 演示一下 总结 前言 在工作总常常需要用到缓存,而redis往往是首选,但是短期的数据缓存一般我们还是会用到本地缓存.本文提供一个我在工作中用到的缓存工具,该工具代码为了演示做了一些调整.如果拿去使用的话,可以考虑做成注入Bean对象,看具体需求了. 环境依赖 先添加maven依赖 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</arti

  • Java内存分配多种情况的用法解析

    这篇文章主要介绍了Java内存分配多种情况的用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Java内存五大区 栈:用于保存函数内部的局部变量,函数形参,一旦超出作用域,就删除 堆:凡是new出来的东西都是存放在堆里,也可以说可变对象(非基本数据类型)都是保存在这里面. 堆里面的东西,都有一个内存(16进制),栈中存放的就是这个16进制的内存值. 堆里面存放的东西都用默认值: 整数:默认值0 浮点数:默认0.0 布尔:默认false 字

  • Java内存模型原子性原理及实例解析

    这篇文章主要介绍了Java内存模型原子性原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 本文就具体来讲讲JMM是如何保证共享变量访问的原子性的. 原子性问题 原子性是指:一个或多个操作,要么全部执行且在执行过程中不被任何因素打断,要么全部不执行. 下面就是一段会出现原子性问题的代码: public class AtomicProblem { private static Logger logger = LoggerFactory.

  • idea插件篇之java内存分析工具(JProfiler)的使用

    前言 在运行java的时候有时候想测试云运行时占用内存情况,这时候就需要使用测试工具查看了.在eclipse里面有 Eclipse Memory Analyzer tool(MAT)插件可以测试,而在idea中也有这么一个插件,就是JProfilerl. 下载安装 打开idea,进入设置界面 安装之后重启即可. 安装成功后查看情况. 这是什么情况呢,这是这个插件启动需要依赖一个可执行的文件,就是源生的JAVA PROFILER 去官网下载 https://www.ej-technologies.

  • Java jar打包工具使用方法步骤解析

    java的jar是一个打包工具,用于将我们编译后的class文件打包起来,这里面主要是举一个例子用来说明这个工具的使用. 在C盘下的temp文件夹下面: 有一个com.pack.surfront的package 这个package下面有一些已经class文件如:Test1.class,Test2.class,Test3.class,其中Test1.class下有一个可执行文件. 我们打开cmd,然后cd temp到temp文件夹下面,因为com.pack.surfront是包路径,不需要再进去然

  • 如何基于LoadingCache实现Java本地缓存

    这篇文章主要介绍了如何基于LoadingCache实现Java本地缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言 Guava是Google开源出来的一套工具库.其中提供的cache模块非常方便,是一种与ConcurrentMap相似的缓存Map. 官方地址:https://github.com/google/guava/wiki/CachesExplained 开始构建 一. 添加依赖 <dependency> <groupI

  • 实现 Java 本地缓存的方法解析

    缓存,我相信大家对它一定不陌生,在项目中,缓存肯定是必不可少的.市面上有非常多的缓存工具,比如 Redis.Guava Cache 或者 EHcache.对于这些工具,我想大家肯定都非常熟悉,所以今天我们不聊它们,我们来聊一聊如何实现本地缓存.参考上面几种工具,要实现一个较好的本地缓存,平头哥认为要从以下三个方面开始. 1.存储集合的选择 实现本地缓存,存储容器肯定是 key/value 形式的数据结构,在 Java 中,也就是我们常用的 Map 集合.Map 中有 HashMap.Hashta

  • 解析springboot整合谷歌开源缓存框架Guava Cache原理

    目录 Guava Cache:⾕歌开源缓存框架 Guava Cache使用 使用压测⼯具Jmeter5.x进行接口压力测试: 压测⼯具本地快速安装Jmeter5.x 新增聚合报告:线程组->添加->监听器->聚合报告(Aggregate Report) Guava Cache:⾕歌开源缓存框架 Guava Cache是在内存中缓存数据,相比较于数据库或redis存储,访问内存中的数据会更加高效.Guava官网介绍,下面的这几种情况可以考虑使用Guava Cache: 愿意消耗一些内存空间

  • Java TimedCache 带时间缓存工具类详解使用

    简述 我们在工作中会碰到需要使用带过期时间的缓存场景.但是使用redis有太重了,毕竟缓存的数据很小,放在内存够够的.hutools提供了TimedCache时间缓存工具,可以实现该场景.下面使用到该组件,并为了适配工作场景,对该工具类做优化升级. Maven依赖 <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>

随机推荐