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

上代码示例:

1、创建Person类

  1. /// <summary>
  2. /// Person类
  3. /// </summary>
  4. public class Person
  5. {
  6. /// <summary>
  7. /// id
  8. /// </summary>
  9. public int Id { get; set; }
  10. /// <summary>
  11. /// 姓名
  12. /// </summary>
  13. public string Name { get; set; }
  14. /// <summary>
  15. /// 是否获得优惠券
  16. /// </summary>
  17. public bool IsGetCoupon { get; set; }
  18. }

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

  1. /// <summary>
  2. /// 获取优惠券
  3. /// </summary>
  4. public static void GetCoupon(Person person)
  5. {
  6. Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},前来领取优惠券", DateTime.Now, person.Name);
  7. //假装业务处理
  8. if (person.IsGetCoupon)
  9. {
  10. //假装业务处理
  11. Thread.Sleep(1000);
  12. Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},已经领取,不可重复领取", DateTime.Now, person.Name);
  13. }
  14. else
  15. {
  16. //假装业务处理
  17. Thread.Sleep(1000);
  18. //领取
  19. person.IsGetCoupon = true;
  20. Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},领取成功", DateTime.Now, person.Name);
  21. }
  22. }

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

  1. /// <summary>
  2. /// Lock获取优惠券
  3. /// </summary>
  4. public static void LockGetCoupon(Person person)
  5. {
  6. Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},前来领取优惠券", DateTime.Now, person.Name);
  7. lock (LockObj)
  8. {
  9. //判断是否已经领取
  10. if (person.IsGetCoupon)
  11. {
  12. //假装业务处理
  13. Thread.Sleep(1000);
  14. Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},已经领取,不可重复领取", DateTime.Now, person.Name);
  15. }
  16. else
  17. {
  18. //假装业务处理
  19. Thread.Sleep(1000);
  20. //领取
  21. person.IsGetCoupon = true;
  22. Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},领取成功", DateTime.Now, person.Name);
  23. }
  24. }
  25. }

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

  1. /// <summary>
  2. /// Mutex,领取
  3. /// </summary>
  4. /// <param name="person"></param>
  5. public static void MutexGetCoupon(Person person)
  6. {
  7. Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},前来领取优惠券", DateTime.Now, person.Name);
  8. using (var mutex = new Mutex(false, person.Id.ToString()))
  9. {
  10. try
  11. {
  12. if (mutex.WaitOne(-1, false))
  13. {
  14. //判断是否已经领取
  15. if (person.IsGetCoupon)
  16. {
  17. //假装业务处理
  18. Thread.Sleep(1000);
  19. Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},已经领取,不可重复领取", DateTime.Now, person.Name);
  20. }
  21. else
  22. {
  23. //假装业务处理
  24. Thread.Sleep(1000);
  25. //领取
  26. person.IsGetCoupon = true;
  27. Console.WriteLine("date:{0:yyyy-MM-dd HH:mm:ss},name:{1},领取成功", DateTime.Now, person.Name);
  28. }
  29. }
  30. }
  31. catch (Exception ex)
  32. {
  33. //TxtLogHelper.WriteLog(ex);
  34. }
  35. finally
  36. {
  37. mutex.ReleaseMutex();
  38. }
  39. }
  40. }
  41. }

3.1、开始测试(不加锁)

  1. static void Main(string[] args)
  2. {
  3. //实例化三个人
  4. Person p1 = new Person { Id = 24, Name = "Kobe" };
  5. Person p2 = new Person { Id = 25, Name = "Rose" };
  6. Person p3 = new Person { Id = 23, Name = "Lebl" };
  7. //开启多线程、模拟三个人同时发起多次领取请求
  8. for (int i = 0; i < 4; i++)
  9. {
  10. new Thread(() =>
  11. {
  12. GetCoupon(p1);
  13. }).Start();
  14. new Thread(() =>
  15. {
  16. GetCoupon(p2);
  17. }).Start();
  18. new Thread(() =>
  19. {
  20. GetCoupon(p3);
  21. }).Start();
  22. }
  23. Console.ReadLine();
  24. }

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

3.2、测试lock锁方法,

  1. private static readonly object LockObj = new object();
  2. static void Main(string[] args)
  3. {
  4. //实例化三个人
  5. Person p1 = new Person { Id = 24, Name = "Kobe" };
  6. Person p2 = new Person { Id = 25, Name = "Rose" };
  7. Person p3 = new Person { Id = 23, Name = "Lebl" };
  8. //开启多线程、模拟三个人同时发起多次领取请求
  9. for (int i = 0; i < 4; i++)
  10. {
  11. new Thread(() =>
  12. {
  13. LockGetCoupon(p1);
  14. }).Start();
  15. new Thread(() =>
  16. {
  17. LockGetCoupon(p2);
  18. }).Start();
  19. new Thread(() =>
  20. {
  21. LockGetCoupon(p3);
  22. }).Start();
  23. }
  24. Console.ReadLine();
  25. }

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

 3.3、测试mutex锁,互斥锁

  1. static void Main(string[] args)
  2. {
  3. //实例化三个人
  4. Person p1 = new Person { Id = 24, Name = "Kobe" };
  5. Person p2 = new Person { Id = 25, Name = "Rose" };
  6. Person p3 = new Person { Id = 23, Name = "Lebl" };
  7. //开启多线程、模拟三个人同时发起多次领取请求
  8. for (int i = 0; i < 4; i++)
  9. {
  10. new Thread(() =>
  11. {
  12. MutexGetCoupon(p1);
  13. }).Start();
  14. new Thread(() =>
  15. {
  16. MutexGetCoupon(p2);
  17. }).Start();
  18. new Thread(() =>
  19. {
  20. MutexGetCoupon(p3);
  21. }).Start();
  22. }
  23. Console.ReadLine();
  24. }

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

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

 

版权声明:本文为bookobe原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/bookobe/p/11229021.html