标签:缓存 list cache list1 System key println Guava out
背景
项目中很多地方使用了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
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。