• 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锁,完美的解决了此类问题。

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

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

  • 相关阅读:
    C++学习笔记(十六):友元
    C++学习笔记(十五):异常
    C++学习笔记(十四):模板
    C++学习笔记(十三):类、包和接口
    C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类
    C++学习笔记(十一):void*指针、类型转换和动态内存分配
    C++学习笔记(十):类
    quartz 实现调度任务 SchedulerManager
    Session 活化与钝化 与tomcat钝化驱动器
    web listener
  • 原文地址:https://www.cnblogs.com/bookobe/p/11229021.html
Copyright © 2020-2023  润新知