C# 针对特定的条件进行锁操作,不用lock,而是mutex
程序员文章站
2022-03-11 08:37:33
C# 解决用户领取优惠券,同一个用户需要加锁验证是否已经领取,不同用户则可以同时领取。 ......
背景:用户领取优惠券,同一个用户需要加锁验证是否已经领取,不同用户则可以同时领取。
上代码示例:
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锁,完美的解决了此类问题。
--------------------------------------------华丽的分割线 --------------------------------------------
感谢各位大佬提出的问题和建议,我确实没有考虑到这些问题。
上一篇: chrome浏览器页面获取绑定返回顶部动画事件插件
下一篇: Map中自定义Key