第7课 缓存策略及并发场景下的分布式锁
课程地址:
https://study.163.com/course/courseMain.htm?courseId=1004873017
本课项目地址:
https://github.com/wechatdeveloper/WechatVideoCourse
课程目标:了解Senparc.Weixin SDK 缓存策略;模拟多线程访问产生的并发,使用分布式锁控制并发
Redis 安装:
-
开启Redis服务,默认端口是6379;redis-cli.exe Set Key , Get Key
-
Redis Desktop Manager: https://github.com/uglide/RedisDesktopManager
-
下载地址:https://github.com/uglide/RedisDesktopManager/releases/tag/0.8.8
-
项目引用 Senparc.Weixin.Cache.Redis
-
Web.config 配置使用缓存:
<add key="Cache_Redis_Configuration" value="localhost:6379" />
-
Global.asax 注册测试号,参考 Senparc Sample 项目配置方法
-
多线程并行,模拟并发
-
多个进程对同1个数据进行更新操作的时候,会产生并发的情况
-
控制并发的产生需要加锁,也就进行更新数据的时候加锁,更新完成后释放锁;加锁的过程中,其他需要访问数据的进行,排队等候
-
建立LockTest方法,方法中对Static类型数据进行更新操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //Static 保存在内存中,页面观察数据变化 2 private static int _count; 3 4 public static int Count 5 { 6 get { return _count; } 7 8 set 9 { 10 _count = value; 11 } 12 } 13 14 public ContentResult LockTest() 15 { 16 //获取当前缓存实例 17 var strategy = CacheStrategyFactory.GetObjectCacheStrategyInstance(); 18 using (strategy.BeginCacheLock("HomeController", "LockTest")) 19 { 20 Thread.Sleep(300); 21 Count++; 22 return Content("Count:" + Count); 23 } 24 }
- 单元测试中,开启多个线程 执行LockTest()方法模拟数据并发,会发现在抢着更新数据,导致脏读
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 private int totalThread = 100; //计划线程要执行20次 2 private int finishedThread = 0; 3 4 [TestMethod] 5 public void LockTest() 6 { 7 //开启多个线程 8 for (int i = 0; i < 100; i++) 9 { 10 Thread thread = new Thread(RunSingleLockTest); 11 thread.Start(); 12 } 13 14 while (finishedThread!= totalThread) 15 { 16 //等待线程执行到100次 17 } 18 19 Console.WriteLine("线程执行完毕:"+totalThread.ToString()); 20 21 } 22 23 private void RunSingleLockTest() 24 { 25 HomeController controller = new HomeController(); 26 27 ContentResult result = controller.LockTest() as ContentResult; 28 29 Console.WriteLine(result.Content); 30 31 finishedThread++; //记得线程执行的次数 32 }
- 执行结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public ContentResult LockTest() { //获取当前缓存实例 var strategy = CacheStrategyFactory.GetObjectCacheStrategyInstance(); using (strategy.BeginCacheLock("HomeController", "LockTest")) { Thread.Sleep(300); Count++; return Content("Count:" + Count); } }
在并发控制下,线程排队执行结果:数据被顺序更新