Java内存缓存工具Guava LoadingCache使用解析
作者:森林木马 发布时间:2023-05-25 08:36:36
这篇文章主要介绍了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()。
来源:https://www.cnblogs.com/owenma/p/12191173.html
猜你喜欢
- 目录1、什么是Java的内存模型2、为什么需要Java内存模型3、Java内存模型及操作规范4、Java内存模型规定的原子操作5、Java内
- Pom依赖<parent> <groupId>org.springframework.bo
- 这篇文章主要介绍了Java List集合排序实现方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 在做多语言版本的时候,日期时间的格式话是一个很头疼的事情,幸好Android提供了DateFormate,可以根据指定的语言区域的默认格式来
- 题目要求思路:模拟Javaclass Solution { public int maximumSwap(int
- 本文实例为大家介绍了几个可用的类,供大家参考,具体内容如下1.SQLHelper类using System;using System.Col
- 背景SpringBoot bean 加载顺序如何查看,想看加载了哪些bean, 这些bean的加载顺序是什么?实际加载顺序不受控制,但会有一
- 本文实例为大家分享了android实现动态显示隐藏进度条的具体代码,供大家参考,具体内容如下调用ProgressUtil.startProg
- 本文实例为大家分享了Java实现聊天机器人完善版的具体代码,供大家参考,具体内容如下Client代码:package GUISocket.c
- 本文实例为大家分享了本地图片或者网络图片高斯模糊效果(毛玻璃效果),具体内容如下首先看效果图1.本地图片高斯模糊2.网络图片高斯模糊gith
- 最近在看 C++ 的方法重载,我就在想 C# 中的重载底层是怎么玩的,很多朋友应该知道 C 是不支持重载的,比如下面的代码就会报错。#inc
- 汉诺(Hanoi)塔问题:古代有一个梵塔,塔内有三个座A、B、C,A座上有n个盘子,盘子大小不等,大的在下,小的在上(如图)。有一个和尚想把
- 在上面的例子中多次使用到了Thread类的join方法。我想大家可能已经猜出来join方法的功能是什么了。对,join方法的功能就是使异步执
- 一、打印直角三角形这个循环控制打印十行空格for (int x = 1; x <= 10; x++) {//因为要打印一个十行的直角三
- 简单介绍synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:1. 修饰一个代码块,被修饰的代码块称为同步语句
- SpringCloud简介Spring cloud是一个基于Spring Boot实现的服务治理工具包,在微服务架构中用于管理和协调服务的微
- 一、背景有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,一般我们检
- 一、前言ConcurrentHashMap的源码采用了一种比较独特的方式对map中的元素数量进行统计,自然是要好好研究一下其原理思想,同时也
- 项目上线之后,如果日志打印的很模糊或者业务逻辑比较复杂,有时候无法定位具体的错误原因,因此可以通过IDEA远程代理进行Debug。线上的代码
- 本文实例讲述了C#检测是否有u盘插入的方法。分享给大家供大家参考。具体如下:该C#代码可监控是否有u盘插入,同时可以监控其它驱动器的变化us