博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# 针对特定的条件进行锁操作,不用lock,而是mutex
阅读量:4589 次
发布时间:2019-06-09

本文共 6060 字,大约阅读时间需要 20 分钟。

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

上代码示例:

1、创建Person类

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

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

///         /// 获取优惠券        ///         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(1000);                Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},已经领取,不可重复领取", DateTime.Now, person.Name);            }            else            {                //假装业务处理                Thread.Sleep(1000);                //领取                person.IsGetCoupon = true;                Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},领取成功", DateTime.Now, person.Name);            }        }

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

///         /// Lock获取优惠券        ///         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(1000);                    Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},已经领取,不可重复领取", DateTime.Now, person.Name);                }                else                {                    //假装业务处理                    Thread.Sleep(1000);                    //领取                    person.IsGetCoupon = true;                    Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},领取成功", DateTime.Now, person.Name);                }            }        }

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

///         /// Mutex,领取        ///         ///         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(-1, false))                    {                        //判断是否已经领取                        if (person.IsGetCoupon)                        {                            //假装业务处理                            Thread.Sleep(1000);                            Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},已经领取,不可重复领取", DateTime.Now, person.Name);                        }                        else                        {                            //假装业务处理                            Thread.Sleep(1000);                            //领取                            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 = 24, Name = "Kobe" };            Person p2 = new Person { Id = 25, Name = "Rose" };            Person p3 = new Person { Id = 23, Name = "Lebl" };            //开启多线程、模拟三个人同时发起多次领取请求            for (int i = 0; i < 4; 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 = 24, Name = "Kobe" };            Person p2 = new Person { Id = 25, Name = "Rose" };            Person p3 = new Person { Id = 23, Name = "Lebl" };            //开启多线程、模拟三个人同时发起多次领取请求            for (int i = 0; i < 4; 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 = 24, Name = "Kobe" };            Person p2 = new Person { Id = 25, Name = "Rose" };            Person p3 = new Person { Id = 23, Name = "Lebl" };            //开启多线程、模拟三个人同时发起多次领取请求            for (int i = 0; i < 4; i++)            {                new Thread(() =>                {                    MutexGetCoupon(p1);                }).Start();                new Thread(() =>                {                    MutexGetCoupon(p2);                }).Start();                new Thread(() =>                {                    MutexGetCoupon(p3);                }).Start();            }            Console.ReadLine();        }

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

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

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

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

转载于:https://www.cnblogs.com/bookobe/p/11229021.html

你可能感兴趣的文章
Linux 进程后台运行的几种方式 screen
查看>>
发送邮件
查看>>
Eclipse Svn 取消某些文件或文件夹的版本控制
查看>>
【模板归纳】网络流及费用流
查看>>
iOS --------Crash 分析(一)
查看>>
冲刺二阶段-个人总结05
查看>>
开源的android客户端,ghost网站
查看>>
《ISCSI集中存储》RHEL6——CE
查看>>
V4L2测试时出现Segmentation fault
查看>>
java基础---->java输入输出流
查看>>
[Apple开发者帐户帮助]九、参考(3)支持的功能(iOS)
查看>>
[Xcode 实际操作]九、实用进阶-(4)计算两个日期间的差值
查看>>
XMLHttpRequest对象的使用
查看>>
windows phone 开发常用小技巧 - 退出应用之升级版(三秒内双击退出)
查看>>
Flask框架学习笔记(API接口管理平台 V2.0)
查看>>
Java学习不走弯路教程(3.从文件内容查询开始)
查看>>
Android环境的搭建及Android Studio的安装
查看>>
12.18 Daily Scrum
查看>>
linux环形buff模拟多线程信号量操作
查看>>
一个基本的curl参数
查看>>