C# 针对特定的条件进行锁操作,不用lock,而是mutex
背景:用户领取优惠券,同一个用户需要加锁验证是否已经领取,不同用户则可以同时领取。
上代码示例:
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(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锁的方法,所有来领优惠券的人,都得排对领(也不好)
- /// <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(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的人就可以同时领取
- /// <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(-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锁,完美的解决了此类问题。