背景:用户领取优惠券,同一个用户需要加锁验证是否已经领取,不同用户则可以同时领取。

上代码示例:

1、创建Person类

    /// <summary>
/// Person类
/// </summary>
public class Person
{
/// <summary>
/// id
/// </summary>
public int Id { get; set; } /// <summary>
/// 姓名
/// </summary>
public string Name { get; set; } /// <summary>
/// 是否获得优惠券
/// </summary>
public bool IsGetCoupon { get; set; }
}

2.1、不加锁的方法(可能会出现重复领取的情况)

        /// <summary>
/// 获取优惠券
/// </summary>
public static void GetCoupon(Person person)
{
Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},前来领取优惠券", DateTime.Now, person.Name);
if (person.IsGetCoupon)
{
//假装业务处理
Thread.Sleep();
Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},已经领取,不可重复领取", DateTime.Now, person.Name);
}
else
{
//假装业务处理
Thread.Sleep();
//领取
person.IsGetCoupon = true;
Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},领取成功", DateTime.Now, person.Name);
}
}

2.2、加lock锁的方法,所有来领优惠券的人,都得排对领(也不好)

        /// <summary>
/// Lock获取优惠券
/// </summary>
public static void LockGetCoupon(Person person)
{
Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},前来领取优惠券", DateTime.Now, person.Name);
lock (LockObj)
{
//判断是否已经领取
if (person.IsGetCoupon)
{
//假装业务处理
Thread.Sleep();
Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},已经领取,不可重复领取", DateTime.Now, person.Name);
}
else
{
//假装业务处理
Thread.Sleep();
//领取
person.IsGetCoupon = true;
Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},领取成功", DateTime.Now, person.Name);
}
}
}

2.3、mutex锁,互斥锁,只有相同id的人,才会排对领取,不同id的人就可以同时领取

        /// <summary>
/// Mutex,领取
/// </summary>
/// <param name="person"></param>
public static void MutexGetCoupon(Person person)
{
Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},前来领取优惠券", DateTime.Now, person.Name);
using (var mutex = new Mutex(false, person.Id.ToString()))
{
try
{
if (mutex.WaitOne(-, false))
{
//判断是否已经领取
if (person.IsGetCoupon)
{
//假装业务处理
Thread.Sleep();
Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},已经领取,不可重复领取", DateTime.Now, person.Name);
}
else
{ //假装业务处理
Thread.Sleep();
//领取
person.IsGetCoupon = true;
Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},领取成功", DateTime.Now, person.Name);
}
}
}
catch (Exception ex)
{
//TxtLogHelper.WriteLog(ex);
}
finally
{
mutex.ReleaseMutex();
}
}
}
}

3.1、开始测试(不加锁)

        static void Main(string[] args)
{
//实例化三个人
Person p1 = new Person { Id = , Name = "Kobe" };
Person p2 = new Person { Id = , Name = "Rose" };
Person p3 = new Person { Id = , Name = "Lebl" }; //开启多线程、模拟三个人同时发起多次领取请求
for (int i = ; i < ; i++)
{
new Thread(() =>
{
GetCoupon(p1);
}).Start();
new Thread(() =>
{
GetCoupon(p2);
}).Start();
new Thread(() =>
{
GetCoupon(p3);
}).Start();
}
Console.ReadLine();
}

测试结果:每个人都重复领取

3.2、测试lock锁方法,

        private static readonly object LockObj = new object();
static void Main(string[] args)
{
//实例化三个人
Person p1 = new Person { Id = , Name = "Kobe" };
Person p2 = new Person { Id = , Name = "Rose" };
Person p3 = new Person { Id = , Name = "Lebl" }; //开启多线程、模拟三个人同时发起多次领取请求
for (int i = ; i < ; i++)
{
new Thread(() =>
{
LockGetCoupon(p1);
}).Start();
new Thread(() =>
{
LockGetCoupon(p2);
}).Start();
new Thread(() =>
{
LockGetCoupon(p3);
}).Start();
}
Console.ReadLine();
}

测试结果:虽然避免了重复领取,但是每个人都的每个请求都要排对。如果用户量大的话,这种方式效率就太低了,所以不推荐。

3.3、测试mutex锁,互斥锁

        static void Main(string[] args)
{
//实例化三个人
Person p1 = new Person { Id = , Name = "Kobe" };
Person p2 = new Person { Id = , Name = "Rose" };
Person p3 = new Person { Id = , Name = "Lebl" }; //开启多线程、模拟三个人同时发起多次领取请求
for (int i = ; i < ; i++)
{
new Thread(() =>
{
MutexGetCoupon(p1);
}).Start();
new Thread(() =>
{
MutexGetCoupon(p2);
}).Start();
new Thread(() =>
{
MutexGetCoupon(p3);
}).Start();
}
Console.ReadLine();
}

测试结果:既避免了重复领取,也避免了堵塞用户请求的情况。见下面截图,Kobe、Rose、Lebl是同时领取的优惠券,但是每个人的重复请求都在排对

总结:mutex锁,完美的解决了此类问题。

--------------------------------------------华丽的分割线 --------------------------------------------

感谢各位大佬提出的问题和建议,我确实没有考虑到这些问题。

C# 针对特定的条件进行锁操作,不用lock,而是mutex的更多相关文章

  1. Microsoft Dynamics CRM 2013 --针对特定实体,取消保存功能(包含自动保存)

    AutoSave 是 Microsoft Dynamics CRM 2013 一个新特性. 但AutoSave的有效范围是[所有实体],不允许针对特定某一实体进行设置. 所以,若想针对特定实体进行设置 ...

  2. 针对特定XML的解析器XMLParser

    一.建立网页库和偏移文件 为文本搜索引擎建立网页库,首先要把所有的网页(这里是文章)格式化,并保存到指定的格式中.如以下格式:   |                                  ...

  3. MySQL 事务的隔离级别及锁操作的一点点演示

    MySQL 版本:5.7 安装环境:MAC OS 一.测试数据 测试数据库:test:测试表:tt CREATE TABLE `tt` ( `id` int(11) DEFAULT NULL, `na ...

  4. html小知识点汇总(浏览器导航上显示图标、div无高度时试着清除浮动、文字环绕图片、字体加粗、div按百分比分、已有的不合适的class,针对特定的标签进行修改)

    1.新点击的网页,在浏览器导航上显示图标: 像这种效果: <head> <meta charset="UTF-8"> <meta name=" ...

  5. 更新xcode后插件失效问题——不针对特定版本的通用解决方法

    一.Xcode更新后插件失效的原理 1.每次更新Xcode后插件都会失效,其实插件都还在这个目录好好的躺着呢: ~/Library/Application Support/Developer/Shar ...

  6. 链表的无锁操作 (JAVA)

    看了下网上关于链表的无锁操作,写的不清楚,遂自己整理一部分,主要使用concurrent并发包的CAS操作. 1. 链表尾部插入 待插入的节点为:cur 尾节点:pred 基本插入方法: do{ pr ...

  7. Mysql优化(出自官方文档) - 第十二篇(优化锁操作篇)

    Mysql优化(出自官方文档) - 第十二篇(优化锁操作篇) 目录 Mysql优化(出自官方文档) - 第十二篇(优化锁操作篇) 1 Internal Locking Methods Row-Leve ...

  8. PHP中针对区域语言标记信息的操作

    相信大家对 zh_CN 这个东西绝对不会陌生,不管是 PHP 中,还是在我们的网页上,都会见到它的身影.其实这就是指定我们的显示编码是什么国家或者地区的,使用何种语言.对于这种区域语言的标记来说,PH ...

  9. **解释器全局锁(Global Interpreter Lock)

    解释器全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程. [解决办法就是多进程和协程(协程 ...

随机推荐

  1. Delphi 7学习开发控件(继承TGraphicControl只画一条线)

    我们知道使用Delphi快速开发,很大的一方面就是其强大的VCL控件,另外丰富的第三方控件也使得Delphi程序员更加快速的开发出所需要的程序.在此不特别介绍一些概念,只记录自己学习开发控件的步骤.假 ...

  2. shell多线程

    a='a1' b='b1' c='c1' d='d1' e='e1' ARR=($a $b $c $d $e) rd=`date +%N` for i in ${ARR[*]} do { ;>& ...

  3. python算法与数据结构-单链表(38)

    一.链表 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括 ...

  4. 分布式数据库中间件 MyCat 搞起来!

    关于 MyCat 的铺垫文章已经写了三篇了: MySQL 只能做小项目?松哥要说几句公道话! 北冥有 Data,其名为鲲,鲲之大,一个 MySQL 放不下! What?Tomcat 竟然也算中间件? ...

  5. 一步到位安装Centos7、配置VMware、连接Xshell

    1.创建虚拟机 1.0 创建新的虚拟机 1.0.1 选择自定义配置 打开VMware,点击创建新的虚拟机. 如下图所示:   1.0.2 选择虚拟机硬件兼容性 如下图所示:   1.0.3 安装客户操 ...

  6. apache出现forbidden

    <Directory /> Options FollowSymLinks AllowOverride All Order deny,allow allow from all Require ...

  7. Kafka学习(一)-------- Quickstart

    参考官网:http://kafka.apache.org/quickstart 一.下载Kafka 官网下载地址 http://kafka.apache.org/downloads 截至2019年7月 ...

  8. HDU 4444:Walk(思维建图+BFS)***

    http://acm.hdu.edu.cn/showproblem.php?pid=4444 题意:给出一个起点一个终点,给出n个矩形的两个对立顶点,问最少需要拐多少次弯可以从起点到达终点,如果不能输 ...

  9. concat的应用

    今天遇到一个问题,有一张车辆信息表,一张车辆品牌表,他们之间的品牌进行关联, 但是车辆信息表中品牌的名称较长,而品牌表名称较短.例如:车辆表:东风标致:品牌表:标致. 为了达到两种表的“模糊关联”. ...

  10. Abnormal build process termination IDEA启动报错

    报错如下: Error:Abnormal build process termination: "C:Program FilesJavajdk1.11.0_1injava" -Xm ...