c# 并发编程系列之六:常见的几种锁及各自的使用场景-Monitor锁
锁的核心作用是用来控制并发环境下对变量和资源的有序访问,c#中常见的锁有如下几种类型:
(1) Monitor
(2) Mutex
(3) ReaderWriterLockSlim
(4) SpinLock
(5) Semaphore
下面我们就来逐个看一看这些不同类型锁的使用场景和使用方式 。
前置条件:
为了使示例更具有参考性,我们照例还是建一个 ASP.NET core Razor的网站项目,
把并发放到网站环境下去运行,这样可以模拟一个多用户的使用场景。项目目录如下:
在此项目下新建 Finish.cshtml 和 Monitor.cshtml 两个文件,其中 Monitor.cshtml 用来执行并发 ,
执行完后跳转到 Finish.cshtml 并将结果显示出来。
1 . 在 Shared 目录下 找到 _Layout.cshtml 文件 , 将 Monitor.cshtml 页面的链接放到菜单中去,
方便我们去点击,代码如下:
<ul class="navbar-nav flex-grow-1"> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Monitor">Monitor</a> </li> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a> </li> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a> </li> </ul>
2 . 在 Monitor.cshtml 页面添加如下的代码,其功能是在表单中放一个SUBMIT按钮,
我们点击后进行 POST提交。
<div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about </p> <form method="post"> <button type="submit">Monitor测试</button> </form> </div>
3 . 相应的我们在 Monitor.cshtml.cs 文件中按约定定义一个 OnPost 方法来响应表单的 POST 操作,代码如下:
public class MonitorModel : PageModel { private int userCount = 10000; //模拟10000个用户同时执行 SUBMIT 操作; private int saleCount = 0; // 定义一个实例变量,模拟记录商品的销量;
public void OnGet() { } public void OnPost() { Parallel.For(0, userCount, i => SaveOrder(i)); // 使用 Parallel.For() 模拟10000个用户并发执行下单操作。 //并发循环完后跳转到完成页面,并将用户数和购买的商品数在 Finish.cshtml 页面显示出来。 string url = string.Format("/Finish?usercount={0}&salecount={1}", userCount, saleCount); Response.Redirect(url); } public void SaveOrder(int i) {
// do something saleCount = saleCount + 1; // 用户下单完成后将商品销量 +1 } }
4. 在 Finish.cshtml 页面接收 OnPost() 方法中传递过来的值然后显示出来,代码如下:
<div>共有 <span style="font-size:18px;">@HttpContext.Request.Query["usercount"]</span> 人购买</div> <br /> <br /> <div>共卖出 <span style="font-size:18px;">@HttpContext.Request.Query["salecount"]</span> 份</div>
至此,我们就完成了一个模拟10000个用户同时在网站下单并完成的操作。
5. 把项目编译之后运行网站,画面如下:
点击按钮,得到如下的结果:
可以看到,结果和我们想象的不一样,卖出的数量不是 10000 份,即使多次执行其数量也小于10000 。
6 . 现在我们用 Monitor 对象 对 SaveOrder(int i) 方法中的语句加锁 ,避免出现实际销量和我们看到的数量
不一致的情况,将 SaveOrder(int i) 改造如下:
private readonly object obj = new object(); public void SaveOrder(int i) { try { Monitor.Enter(obj); saleCount = saleCount + 1; } finally { Monitor.Exit(obj); } }
编译后刷新页面,然后再次点击按钮,得到结果如下:
和我们期望的结果一样。
接下来我们分析一下上述意外情况产生的原因及另外几种改进写法的不同之处。
(未完待续...)
原文地址:https://www.cnblogs.com/pfm33/p/14980855.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android播放音乐案例分享
- linux crm部署代码详解
- Android自定义WaveProgressView实现水波纹加载需求
- CentOS8下的root密码快速修改方法
- Android开发之自定义刮刮卡实现代码
- Android ScrollView无法填充满屏幕的解决办法
- Android 监听屏幕是否锁屏的实例代码
- Android实现水波纹控件的方法
- Android中GridView布局实现整体居中方法示例
- Android SharedPreferences四种操作模式使用详解
- Ubuntu18.04下将 磁盘挂载在某目录下
- Android编程之绘图canvas基本用法示例
- Android 编译出错版本匹配问题解决办法
- Linux(CentOS7)使用 RPM 安装 mysql 8.0.11的教程
- Android Adapter里面嵌套ListView实例详解