ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Guava缓存list集合进行滤操作导致多次获取相同key返回数据不一致问题

2022-05-17 20:32:45  阅读:202  来源: 互联网

标签:缓存 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. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有