Guava缓存list集合进行滤操作导致多次获取相同key返回数据不一致问题
作者:互联网
背景
项目中很多地方使用了Guava Cache,用于加速读取频繁访问的热点数据。
最近项目组中遇到一个"诡异"的问题,多次获取Cache中相同key的数据,返回值不同。
分析
通过查看日志和排查代码,发现有多个地方获取缓存,有的地方获取缓存数据还进行了过滤处理,
正是这些处理改变缓存值,导致其它地方获取数据发生变更,跟预期不一致。
模拟
LoadingCache<String, List<Integer>> cache = CacheBuilder.newBuilder()
.maximumSize(1)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build(new CacheLoader<String, List<Integer>>() {
@Override
public List<Integer> load(String s) throws Exception {
return Lists.newArrayList(1, 2, 3);
}
});
首先定义一个LoadingCache
,key是String
类型,返回List<Integer>
类型;
通过maximumSize(1)
限制缓存中只有1个值;
返回模拟的列表[1,2,3]。
// test case1
List<Integer> list1 = cache.get("all");
System.out.println(list1);
list1.removeIf(o -> o.equals(1));
System.out.println(list1);
List<Integer> list2 = cache.get("all");
System.out.println(list2);
输出结果为:
[1, 2, 3]
[2, 3]
[2, 3]
第1次获取缓存后通过removeIf
去掉了元素1,再次获取缓存发现结果集跟着改变了。
// test case2
list1 = cache.get("all");
System.out.println(list1);
list1 = Lists.newArrayList(1);
System.out.println(list1);
list2 = cache.get("all");
System.out.println(list2);
输出结果为:
[1, 2, 3]
[1]
[1, 2, 3]
第1次获取缓存后通过=
号赋值修改list1
变量引用地址,再次获取缓存结果集不变。
// test case3
System.out.println(StringUtils.center("case3", 50, "-"));
list1 = cache.get("all");
System.out.println(list1);
list1 = list1.stream().filter(o -> !o.equals(1)).collect(Collectors.toList());
System.out.println(list1);
list2 = cache.get("all");
System.out.println(list2);
输出结果为:
[1, 2, 3]
[2, 3]
[1, 2, 3]
第1次获取缓存后,通过stream流filter方式过滤,并生成新的list,再次获取缓存结果集不变。
完整代码如下:
/**
* @author cdfive
*/
public class CacheTest2 {
public static void main(String[] args) throws Exception {
LoadingCache<String, List<Integer>> cache = CacheBuilder.newBuilder()
.maximumSize(1)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build(new CacheLoader<String, List<Integer>>() {
@Override
public List<Integer> load(String s) throws Exception {
return Lists.newArrayList(1, 2, 3);
}
});
// test case1
System.out.println(StringUtils.center("case1", 50, "-"));
List<Integer> list1 = cache.get("all");
System.out.println(list1);
list1.removeIf(o -> o.equals(1));
System.out.println(list1);
List<Integer> list2 = cache.get("all");
System.out.println(list2);
list1 = null;
cache.invalidateAll();
// test case2
System.out.println(StringUtils.center("case2", 50, "-"));
list1 = cache.get("all");
System.out.println(list1);
list1 = Lists.newArrayList(1);
System.out.println(list1);
list2 = cache.get("all");
System.out.println(list2);
// test case3
System.out.println(StringUtils.center("case3", 50, "-"));
list1 = cache.get("all");
System.out.println(list1);
list1 = list1.stream().filter(o -> !o.equals(1)).collect(Collectors.toList());
System.out.println(list1);
list2 = cache.get("all");
System.out.println(list2);
}
}
总结
使用Guava Cache时应注意:
- 当缓存类似list集合或者对象时,获取缓存后如果修改了缓存对象,会实际作用到缓存值,对再次获取缓存有影响
- 如缓存list集合数据获取缓存后需要过滤,应慎用
removeIf
方法,可考虑stream流filter方式过滤
标签:缓存,list,cache,list1,System,key,println,Guava,out 来源: https://www.cnblogs.com/cdfive2018/p/16276306.html