简介
缓存是提高系统性能的一种重要手段,而lru(Least Recently Used,最近最少使用)缓存策略又是缓存中很重要的一种缓存过期策略。
随着各种框架和产品的发展与迭代,目前可以供我们选择的缓存实现方式也多种多样,至于最种选择哪种实现方式,往往需要结合着项目自身的实际情况来考虑。
本文将根据我的实际使用经验,对JAVA项目中常用的三种缓存实现方式进行一个简短的描述与总结。
- 其于LinkedHashMap缓存的实现方式
- guava包下的cache
- redis中的lru缓存实现方式
其于LinkedHashMap缓存的实现方式
使用方式
继承LinkedHashMap,并实现removeEldestEntry方法即可
示例如下:
public class LinkedHashMapLruTest {
public static class MyLruCache<K, V> extends LinkedHashMap<K, V> {
private Integer maxSize;
public MyLruCache(Integer maxSize) {
this.maxSize = maxSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > this.maxSize;
}
}
public static void main(String[] args) {
MyLruCache<String, String> cacheMap = new MyLruCache<>(6);
//放入缓存
for (int i = 1; i <= 10; i++) {
cacheMap.put(i + "", i + "");
if (i % 2 == 0) {
System.out.println(i + "热点数据:[2]");
cacheMap.put(2 + "", "我是热点数据2");
}
if (i % 3 == 0) {
System.out.println(i + "热点数据:[3]");
cacheMap.put(3 + "", "我是热点数据3");
}
}
//输出
System.out.println("----------------------");
Set<String> keySet = cacheMap.keySet();
for (String keyName : keySet) {
System.out.println(keyName);
}
}
}
示例输出结果:
2热点数据:[2]
3热点数据:[3]
4热点数据:[2]
6热点数据:[2]
6热点数据:[3]
8热点数据:[2]
9热点数据:[3]
10热点数据:[2]
----------------------
7
8
2
9
3
10
guava包下的cache
使用方式
直接到guava的github官网,找到pom,直接引入即可
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
引入后,直接敲代码试一下:
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.Set;
public class GuavaCacheTest {
public static void main(String[] args) {
Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(6).build();
//放入缓存
for (int i = 1; i <= 10; i++) {
cache.put(i + "", i + "");
if (i % 2 == 0) {
System.out.println(i + "热点数据:[2]");
// cache.put(2 + "", "我是热点数据2");
cache.getIfPresent("2");
}
if (i % 3 == 0) {
System.out.println(i + "热点数据:[3]");
// cache.put(3 + "", "我是热点数据3");
cache.getIfPresent("3");
}
}
//输出
System.out.println("----------------------");
Set<String> keySet = cache.asMap().keySet();
for (String keyName : keySet) {
System.out.println(keyName);
}
}
}
示例输出结果:
2热点数据:[2]
3热点数据:[3]
4热点数据:[2]
6热点数据:[2]
6热点数据:[3]
8热点数据:[2]
9热点数据:[3]
10热点数据:[2]
----------------------
2
10
3
9
8
7
redis中的lru策略
使用方式
redis官方文档如下:
https://redis.io/documentation
关于redis中lru的描述地址为:
https://redis.io/topics/lru-cache
redis中关于如何开启缓存key的lru淘汰策略可以上面的地址中查看具体的方法
It is possible to set the configuration directive using the redis.conf file, or later using the CONFIG SET command at runtime.
可以通过设置redis.conf文件或CONFIG SET命令来临时设置
其中redis.conf的配置参考文件可通过github查看,地址为:https://raw.githubusercontent.com/redis/redis/6.0/redis.conf
简短对比
类型 | 部分特点 |
---|---|
其于LinkedHashMap实现缓存 | 代码简单,开发快捷,但线程不安全,每次延长某个缓存得再次使用put,或重写accessOrder为true后调用get方法也能延长 |
guava包下的cache | 需要导第三方包,但功能强大,除了支持lru外还支持多种缓存策略,get或put都可对缓存续期 |
redis中的lru内存淘汰策略 | 适合分布式应用并需要单独部署,通过指定的最大内存来进行内存淘汰判断 |
简单对比后,感觉不管哪种lru的缓存方式都各有特点。
如果应用简单直接用LinkedHashMap也就可以了
但如果想做到更细粒度化的缓存(如:还需支持定时过期)推荐使用guava下的cache,毕竟这个比自己实现的LinkedHashMap缓存强很多
如果项目是分布式的应用缓存,那就必须得上redis了。不管是lru还是ttl的缓存过期,它都能搞定