学习使用Guava Cache
官方文档:https://github.com/google/guava/wiki/CachesExplained
目录
二、快速入门
2.1、引入依赖
2.2、第一个示例
2.3、批量操作
三、拓展
3.1、移除监听器
3.2、刷新缓存
3.3、自定义刷新的操作
一、guava cache介绍
对于常见的cache(缓存),比如memecache、redis、tair这些中间件,也有jdk的一些类库可以当做缓存使用,比如实现了ConcurrentMap接口的ConcurrentHashMap。
ConcurrentHashMap虽然可以让我们在程序中缓存一些数据,但是这些数据其实永远不会过期,除非手动删除,否则数据将一直存在于内存中。
而guava cache(LocalCache,本地缓存),也是实现了ConcurrentMap的类,但他和ConcurrentHashMap的区别在于,guava cache可以设置数据过期以及淘汰机制,更加符合一般的应用需求。
guava cache,是一个本地缓存,也就是说,他的数据是存放在机器内存,这个机器,就是JVM所在的机器(会占用一部分内存),而不是像redis那样专门做缓存的机器。
二、快速入门
2.1、引入依赖
guava cahce是guava的子模块。
guava仓库地址:https://mvnrepository.com/artifact/com.google.guava/guava
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.0-jre</version>
</dependency>
2.2、第一个示例
下面是一个简单的示例:
package cn.ganlixin.guava; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.junit.Test; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testLoadingCache() throws ExecutionException {
// 创建缓存(容器)
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
// 数据写入1分钟后失效
.expireAfterWrite(1, TimeUnit.MINUTES)
// 支持缓存项的数据最大为3个
.maximumSize(3)
// 实现CacheLoader,当在缓存中未找到所需的缓存项时,会执行CacheLoader的load方法加载缓存。
.build(new CacheLoader<String, String>() {
// 方法的返回值会被缓存,注意,返回null时,会抛异常
@Override
public String load(String key) throws Exception {
System.out.println("key:" + key + " 未找到,开始加载....");
return key + "-" + key;
}
}); // 加入缓存
cache.put("Java", "spring");
cache.put("PHP", "swoole"); // 从缓存中获取值
String res1 = cache.get("Java"); // get方法需要抛出ExecutionException异常
// cache.getUnchecked("Java"); // 功能和get一样,但是不会throw异常
System.out.println(res1);
// 输出:spring // 缓存中为存放key为Golang的缓存项,所以进行加载
String res2 = cache.get("Golang");
System.out.println(res2);
// key:Golang 未找到,开始加载....
// Golang-Golang // Golang的缓存项前面已经加载过了,且没有被清除,所以这次直接获取到对应的value
String res3 = cache.get("Golang");
System.out.println(res3);
// Golang-Golang // 前面添加了3个缓存项(已经达到设置上限,此时再添加缓存项,将会触发淘汰)
cache.put("Node", "KOA");
System.out.println(cache.get("PHP")); // PHP在cache中已被淘汰
// key:PHP 未找到,开始加载....
// PHP-PHP // 查询缓存,如果未找到,不会触发加载操作,而是范围null。
String res4 = cache.getIfPresent("key");
System.out.println(res4); // null
}
}
2.3、批量操作
guava cache支持批量添加、查询、清除操作。
package cn.ganlixin.guava; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import org.junit.Test; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testMultiple() throws ExecutionException {
// 创建缓存
LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder()
.maximumSize(2) // 最大缓存项数量为2
.expireAfterWrite(10, TimeUnit.SECONDS) // 数据写入10秒过期
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
System.out.println("key:" + key + " 未找到,开始加载....");
return key + "-" + key;
}
}); Map<String, String> map = new HashMap<>();
map.put("one", "111111");
map.put("two", "222222");
map.put("three", "3333333");
// 批量添加
loadingCache.putAll(map); List<String> keys = new ArrayList<>();
keys.add("one");
keys.add("two");
// 批量获取
ImmutableMap<String, String> allData = loadingCache.getAll(keys);
System.out.println(allData);
// {one=one-one, two=222222} // 批量清除
loadingCache.invalidateAll(keys);
loadingCache.invalidateAll(); // 全量清除
}
}
三、拓展
3.1、移除监听器
移除监听器,是指监听缓存项,当缓存项被清除时,执行指定对操作。
package cn.ganlixin.guava; import com.google.common.cache.*;
import org.junit.Test; import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testRemoveListender() { LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(2)
.expireAfterWrite(1, TimeUnit.MINUTES)
// 绑定"移除监听器",当元素被清除时,执行onRemoval方法
.removalListener(new RemovalListener<String, String>() {
@Override
public void onRemoval(RemovalNotification removalNotification) {
Object key = removalNotification.getKey();
Object val = removalNotification.getValue();
System.out.println("被清除的元素,key:" + key + ", val:" + val); }
})
// 当在缓存中未找到key时,执行load操作。
.build(new CacheLoader<String, String>() {
// 当key未找到时,执行的加载操作
@Override
public String load(String key) throws Exception {
System.out.println("未找到key:" + key + ",开始加载...");
return key + key;
}
}); cache.put("one", "111111");
cache.put("two", "123456"); // 继续添加元素,会触发清理操作,触发移除监听器
cache.put("three", "2233333");
// 输出:被清除的元素,key:one, val:111111 String res = cache.getUnchecked("four");
System.out.println(res);
// 输出
// 未找到key:four,开始加载...
// 被清除的元素,key:two, val:123456
// fourfour
}
}
3.2、刷新缓存
刷新缓存,是指一个缓存项写入缓存后,经过一段时间(设置的刷新间隔),再次访问该缓存项的时候,会刷新该缓存项,可以理解为将该项的key取出,执行CacheLoader的load方法,然后将返回值替换旧的值。
可以在创建缓存的时候,设置刷新缓存的时间:
package cn.ganlixin.guava; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.junit.Test; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testRefresh() throws InterruptedException, ExecutionException {
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(2)
// 设置刷新的时机
.refreshAfterWrite(2, TimeUnit.SECONDS)
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
System.out.println("key:" + key + " 未找到,开始加载....");
return key + "-" + key;
}
}); cache.put("one", "11111");
cache.put("two", "22222"); // 休眠3秒
Thread.sleep(3000L); System.out.println(cache.get("one"));
//key:one 未找到,开始加载....
//one-one System.out.println(cache.get("two"));
//key:two 未找到,开始加载....
//two-two
}
}
需要注意的是,以上面代码为例,并不是设置写入2秒后,就会被刷新,而是当写入2秒后,且再次被访问时,才会被刷新;如果一个缓存项写入的时间超过2秒,但是一直没有访问该项,那么这一项是不会被刷新的。这与Memecache和Redis的原理类似。
3.3、自定义刷新缓存的操作
前面内容中,提到可以使用设置refreshAfterWrite()设置数据写入多久后,再次被访问时,会被刷新,其实,我们可以对于刷新操作自定义,只需要重写CacheLoader的reload方法即可。
package cn.ganlixin.guava; 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 org.junit.Test; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testReload() throws InterruptedException {
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(2)
// 设置刷新的时机
.refreshAfterWrite(2, TimeUnit.SECONDS)
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
System.out.println("key:" + key + " 未找到,开始加载....");
return key + "-" + key;
} // 刷新缓存时,执行的操作
@Override
public ListenableFuture<String> reload(String key, String oldValue) throws Exception {
System.out.println("刷新缓存项,key:" + key + ", oldValue:" + oldValue);
return super.reload(key, oldValue);
}
}); cache.put("hello", "world");
Thread.sleep(3000L); System.out.println(cache.getUnchecked("hello"));
// 刷新缓存项,key:hello, oldValue:world
// key:hello 未找到,开始加载....
// hello-hello
}
}
学习使用Guava Cache的更多相关文章
- spring boot guava cache 缓存学习
http://blog.csdn.net/hy245120020/article/details/78065676 ****************************************** ...
- Guava学习笔记:Guava cache
缓存,在我们日常开发中是必不可少的一种解决性能问题的方法.简单的说,cache 就是为了提升系统性能而开辟的一块内存空间. 缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用 ...
- guava cache学习
Guava Cache与ConcurrentMap很相似,但也不完全一样.最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除.相对地,Guava Cache为了限制内存占 ...
- Spring cache简单使用guava cache
Spring cache简单使用 前言 spring有一套和各种缓存的集成方式.类似于sl4j,你可以选择log框架实现,也一样可以实现缓存实现,比如ehcache,guava cache. [TOC ...
- 是什么让spring 5放弃了使用Guava Cache?
一路走来,Spring社区从刚开始的核心模块一直发展到现在,最近Sping5也完成了M5的发布, 相信不久之后第一个RELEASE版本也会发布.里面有很多特性是和即将要发布的JAVA 9息息相关的.今 ...
- Guava Cache探索及spring项目整合GuavaCache实例
背景 对于高频访问但是低频更新的数据我们一般会做缓存,尤其是在并发量比较高的业务里,原始的手段我们可以使用HashMap或者ConcurrentHashMap来存储. 这样没什么毛病,但是会面临一个问 ...
- Spring配置cache(concurrentHashMap,guava cache、redis实现)附源码
在应用程序中,数据一般是存在数据库中(磁盘介质),对于某些被频繁访问的数据,如果每次都访问数据库,不仅涉及到网络io,还受到数据库查询的影响:而目前通常会将频繁使用,并且不经常改变的数据放入缓存中,从 ...
- Guava Cache详解
适用性 缓存在很多场景下都是相当有用的.例如,计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存 Guava Cache与ConcurrentMap很相似,但也不 ...
- [Java 缓存] Java Cache之 Guava Cache的简单应用.
前言 今天第一次使用MarkDown的形式发博客. 准备记录一下自己对Guava Cache的认识及项目中的实际使用经验. 一: 什么是Guava Guava工程包含了若干被Google的 Java项 ...
随机推荐
- LeetCode No.103,104,105
No.103 ZigzagLevelOrder 二叉树的锯齿形层次遍历 题目 给定一个二叉树,返回其节点值的锯齿形层次遍历.(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行). ...
- css3应用
画出一个禁行标志 border-radius: 50%; width: 100px; height: 100px; border: 10px solid red; background: linear ...
- 非线程安全的HashMap 和 线程安全的ConcurrentHashMap
在平时开发中,我们经常采用HashMap来作为本地缓存的一种实现方式,将一些如系统变量等数据量比较少的参数保存在HashMap中,并将其作为单例类的一个属性.在系统运行中,使用到这些缓存数据,都可以直 ...
- java正则(贪婪、勉强)
贪婪.勉强和侵占量词间的不同 在贪婪.勉强和侵占三个量词间有着细微的不同. 贪婪(*, ?, +):读入整个串,从后往前匹配 勉强(*?, ??, +?):从前往后匹配 侵占(*+, ?+, ++): ...
- xpath-helper 插件下载
链接:https://pan.baidu.com/s/1YuTGrdwwAKQd2sIcuarBHQ 提取码:qb8p
- python库之——sklearn
机器学习库sklearn 官方documentation(资料)中分为不同的部分: 其中我们主要讲User Guide(机器学习算法理论介绍).API(程序实现方法): 一.User Guide ht ...
- [LC] 66. Plus One
Given a non-empty array of digits representing a non-negative integer, plus one to the integer. The ...
- [rope大法好] STL里面的可持久化平衡树--rope
简单用法: #include <ext/rope> using namespace __gnu_cxx; int a[1000]; rope<int> x; rope<i ...
- 默认的Settings.xml文件(无修改过)-Maven
Tip: 当什么都不作修改时,默认是从Maven中央仓库进行下载,https://repo.maven.apache.org/maven2. 打开maven源码下的lib文件夹,找到maven-mod ...
- Python---14面向对象高级编程(__slots__&@property)
一.使用__slots__ 正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性.先定义class: class Stude ...