项目开发中,用到了缓存,其中的一个列表项,可能要多线程处理,就有了下面的想法,具体的问题在代码中有详细说明,见下文。
1 static void Main(string[] args) { 2 3 4 5 测试缓存的想法(); 6 7 Console.WriteLine("测试结束!"); 8 Console.ReadKey(); 9 } 10 11 /// <summary> 12 /// 静态的缓存,测试缓存是否存放的指针 13 /// </summary> 14 private static MemoryCache memoryCache = MemoryCache.Default; 15 16 private static void 测试缓存的想法() { 17 18 Console.WriteLine("创建一个测试的整型列表:"); 19 20 List<int> ints = new List<int>(); 21 22 Console.WriteLine("列表中放入{1,2,3} 3个数字"); 23 24 ints.Add(1); 25 ints.Add(2); 26 ints.Add(3); 27 28 //缓存的策略,10分钟,测试够用了 29 var policy = new CacheItemPolicy(); 30 policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(10); 31 32 Console.WriteLine("将整型列表放入缓存,缓存10分钟:"); 33 memoryCache.Set("key", ints, policy); 34 35 //不取出更改原有的列表,去除第2个数字 36 Console.WriteLine("更新原有列表的数据,去除第2个数字,缓存不做处理:"); 37 ints.Remove(2); 38 39 Console.WriteLine("从缓存中取出对应的缓存列表,打印缓存列表项"); 40 41 var result = (List<int>)memoryCache.Get("key"); 42 43 result.ForEach(r => { Console.WriteLine(r); }); 44 45 Console.WriteLine("-----------------第一阶段测试完成------------------------"); 46 Console.WriteLine(""); 47 48 Console.WriteLine("直接处理缓存列表项,去除第1个数字,并且没有再次保存至缓存的动作:"); 49 result.Remove(1); 50 51 Console.WriteLine("打印缓存中的列表项:"); 52 //下面这句有没有,打印的结果是一样的 53 result = (List<int>)memoryCache.Get("key"); 54 result.ForEach(r => { Console.WriteLine(r); }); 55 56 Console.WriteLine(""); 57 Console.WriteLine("打印原列表项:"); 58 59 ints.ForEach(r => { Console.WriteLine(r); }); 60 61 Console.WriteLine("-----------------第二阶段测试完成------------------------"); 62 63 Console.WriteLine("直接操作原有的列表项,添加一个数字4:"); 64 ints.Add(4); 65 66 Console.WriteLine("不重新取缓存项,打印缓存中的列表项:"); 67 //下面这句有没有,打印的结果是一样的 68 result.ForEach(r => { Console.WriteLine(r); }); 69 70 Console.WriteLine(""); 71 Console.WriteLine("打印原列表项:"); 72 73 ints.ForEach(r => { Console.WriteLine(r); }); 74 75 Console.WriteLine("-----------------第三阶段测试完成------------------------"); 76 77 /* 78 * 结论: 79 * 80 * 缓存内部存放的对象的指针,不管是原对象的直接修改,或对缓存项的修改 81 * 只要缓存的指针没有发生变化,对此对象的修改会同步传导到缓存及原对象的指针 82 */ 83 }
其实这个测试并没有什么新意,在.Net中关于对象在内存中的存放位置相关的文章中有明确的说明:
对象放在托管堆上,对象本身有个指针指向这个托管堆,(虽然这个指针可能会随着GC的运行发生动态调整,但是我们仍然可以当做指针来理解)
上面测试中的缓存项与原有的列表项,其实指向的是同一块内存,对其中的任何修改,会同时传导到两个对象。理解不了需要看一下.Net的底层的相关知识
结合C语言的指针理解起来其实更容易一些。
我想要多线程处理这个缓存列表安全,此时可以换用 ConcurrentBag ,没见过这个对象的同学可以参考MSDN,这是一个多线程操作安全的无序集合。
此时便可以多线程得到这个缓存项(ConcurrentBag)的 对象,做相应的操作即可,问题解决。
语言表达能力有限,欢迎批评指正,有砖轻轻拍。