【C#|.NET】lock(this)其实是个坑
来自 【C#|.NET】lock(this)其实是个坑
这里不考虑分布式或者多台负载均衡的情况只考虑单台机器,多台服务器可以使用分布式锁。出于线程安全的原因,很多种场景大家可能看代码中看到lock的出现,尤其是在资金类的处理环节。 但是lock(this)真的达到你的需求了吗?下面用实例来说明
理论常识不多说,回到业务场景,举个例子我们的需求一般就是在某个订单进入某个安全优先级比较高的流程时要针对这笔订单做到线程互斥。至于原因,这里再插一个概念,大部分orm在做更新操作时,实际上做的是全参数更新,所谓全参数更新,假如一个订单表上有10个字段,我们只需要更新其中的一个金额字段,但是在传统orm框架中实际上在订单的实体类中赋值了所有字段而在更新操作中这些字段全部参与了更新,所以在高并发的场景下,如果有2个线程针对同一个订单操作,并且没有额外的保护程序(例如数据库锁、版本号等)那么在这种传统框架下后一个线程更新可能就会覆盖掉前一个线程的操作。因此lock的手段可以看成是一道保护墙。 那么接下来我们通过实例看一下lock4种不同方式(并非4种类别)之间的区别
代码很简单 在结果截图后直接附上
1. Lock(this)
可以看出lock(this),如果this是个普通的类非静态非单例,那么lock(this)并不满足我们的需求,甚至除了当前线程并看不出有任何作用。
2. Lock(LockString)
Lock(LockString) 从结果上来看比较契合要求,对于同一笔订单做到的线程互斥,对于不同订单即使用到了同一个类也不干扰。不过根据大家的回复意见LockString并不适合锁。
3. Lock(Object)
Lock(Object)和Lock(this)一样,因为根本原因2者方式是相同的。推荐!
4. Lock(StaticObject)
Lock(StaticObject) 实现了对于同一笔的订单线程互斥,但是不符合的是对于不同笔的订单同样进行了互斥。
结论一目了然,理论的内容不赘述。下面贴代码
class Program
{
const string firstOrderId = "001";
const string secondOrderId = "002";
const string thirdOrderId = "003";
static void Main()
{
test(LockType.LockThis);
//test(LockType.LockString);
//test(LockType.LockObject);
//test(LockType.LockStaticObject);
Console.ReadLine();
}
static void test(LockType lockType)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("------------测试相同订单------------");
Console.ForegroundColor = ConsoleColor.White;
OrderPay(firstOrderId, 1, lockType);
OrderPay(firstOrderId, 2, lockType);
OrderPay(firstOrderId, 3, lockType);
Thread.Sleep(10000);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("------------测试不同订单------------");
Console.ForegroundColor = ConsoleColor.White;
OrderPay(firstOrderId, 1, lockType);
OrderPay(secondOrderId, 1, lockType);
OrderPay(thirdOrderId, 1, lockType);
}
static void OrderPay(string orderId, int threadNo, LockType lockType)
{
new Thread(() => new Payment(orderId, threadNo).Pay(lockType)).Start();
Thread.Sleep(10);
}
}
public class Payment
{
private readonly string LockString;
public readonly int ThreadNo;
private readonly Object LockObj = new object();
private static readonly Object StaticLockObj = new object();
public Payment(string orderID, int threadNo)
{
LockString = orderID;
ThreadNo = threadNo;
}
public void Pay(LockType lockType)
{
ShowMessage("等待锁资源");
switch (lockType)
{
case LockType.LockThis:
lock (this)
{
showAction();
}
break;
case LockType.LockString:
lock (LockString)
{
showAction();
}
break;
case LockType.LockObject:
lock (LockObj)
{
showAction();
}
break;
case LockType.LockStaticObject:
lock (StaticLockObj)
{
showAction();
}
break;
}
ShowMessage("释放锁");
}
private void showAction()
{
ShowMessage("进入锁并开始操作");
Thread.Sleep(2000);
ShowMessage("操作完成,完成时间为" + DateTime.Now);
}
private void ShowMessage(string message)
{
Console.WriteLine(String.Format("订单{0}的第{1}个线程 {2}", LockString, ThreadNo, message));
}
}
public enum LockType
{
LockThis = 0,
LockString = 1,
LockObject = 2,
LockStaticObject = 3
}
- 行受影响 是什么意思
- c++课程设计(日历)
- 一个程序,让你理解运算符重载操作
- HDUOJ ---1423 Greatest Common Increasing Subsequence(LCS)
- 在运算符重载++,--,+=,-=...
- 排序一栏(总结帖)
- 编程思想 之「异常及错误处理」
- nyoj-----284坦克大战(带权值的图搜索)
- nyoj-----42一笔画问题
- hdu-------1081To The Max
- nyoj------170网络的可靠性
- HDUOJ-------1052Tian Ji -- The Horse Racing(田忌赛马)
- 初学Java之Pattern与Matcher类
- 初学java之StringBuffer类的常用方法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 3分钟短文:Laravel说要用软删除,可不要真删
- leetcode队列之设计循环双端队列
- MySQL8.0的binlog详解
- Flutter NestedScrollView实现的一个经典滑动折叠头部图片的效果
- Maven 编译拷贝资源的时候提示 UTF-8 编码信息
- Qt音视频开发30-Onvif事件订阅
- 干掉 Navicat:正版,MySQL 官方客户端真香!
- CentOS 搭建 K8S 环境教程,一次性成功,收藏了!
- IDEA 真香!找出全部未被使用的代码只用了 2 秒钟!
- ArrayList 插入 1000w 条数据之后,我怀疑了 Java 虚拟机。。。
- 本地存储应用案例 ToDoList
- jQuery 插件
- 本周AI热点回顾:RTX3080被黄牛炒上天;百度资本助力AI 制药,已有十几位博士加入;百度联手打造AI沉浸互动展中国首秀
- 线段树
- 乘法表中第k小的数