概述
lock 语句获取给定对象的互斥lock,执行语句块,然后释放lock。持有lock时,持有lock的线程可以再次获取并释放lock。阻止任何其他线程获取lock并等待释放lock.
lock语句具有以下格式
lock (x)
{
// Your code...
}
其中x是引用类型的表达式。它完全等同于
object __lockObj = x;
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
// Your code...
}
finally
{
if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}
由于该代码使用try…finally块,即使在lock语句的正文中引发异常,也会释放lock。
在lock语句的正文中不能使用await运算符(原因如下:)
只能在通过 async 关键字修改的方法、lambda 表达式或匿名方法中使用 await 运算符。 在异步方法中,不能在同步函数的主体、lock 语句块内以及不安全的上下文中使用 await 运算符。
准则
当同步对共享资源的线程访问时,请锁定专用对象实例(例如,private readonly object blanceLock=new object();)或另一个不太可能被代码无关部分用作lock对象的实例。避免对不同的共享资源使用相同的lock对象实例,因为这可能导致死锁或锁征用。具体而言,避免将以下对象作用lock对象:
- this(调用方可能将其用作lock)
- Type实例(可以通过typeof运算符或反射获取)。
- 字符串实例,包括字符串文本,(这些可能是暂存的)。
尽可能缩短持有锁的时间,以减少锁争用。
示例
以下示例定义了一个Account类,该类通过锁定专用的blanceLock实例来同步对其专用的blance字段的访问。使用相同的实例进行锁定可确保尝试同时的调用Debit或Credit方法的两个线程无法同事更新blance字段
using System;
namespace _84lock
{
public class Account
{
private readonly object balanceLock = new object();
private decimal balance;
public Account(decimal initialBalance) => balance = initialBalance;
public decimal Debit(decimal amount)
{
if (amount < 0)
{
throw new ArgumentOutOfRangeException(nameof(amount), "The debit amount cannot be negative");
}
decimal appliedAmount = 0;
lock (balanceLock)
{
if (balance >= amount)
{
balance -= amount;
appliedAmount = amount;
}
}
return appliedAmount;
}
public void Credit(decimal amount)
{
if (amount < 0)
{
throw new ArgumentOutOfRangeException(nameof(amount), "The credit amount cannot be negative.");
}
lock (balanceLock)
{
balance += amount;
}
}
public decimal GetBalance()
{
lock (balanceLock)
{
return balance;
}
}
}
}
using System;
using System.Threading.Tasks;
namespace _84lock
{
class Program
{
static async Task Main(string[] args)
{
var account = new Account(1000);//初始值,设置为100
//1.创建100个线程任务,去执行update操作
var tasks = new Task[100];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Run(() => Update(account));
}
await Task.WhenAll(tasks);//2.此处是等待完成任务,以上线程任务,完成之后,继续下面的逻辑代码
//Update(account);
Console.WriteLine($"Account's balance is {account.GetBalance()}");
Console.ReadKey();
}
static void Update(Account account)
{
decimal[] amounts = { 0, 2, -3, 6, -2, -1, 8, -5, 11, -6 };
foreach (var amount in amounts)
{
if (amount >= 0)
{
account.Credit(amount);
}
else
{
account.Debit(Math.Abs(amount));
}
}
}
}
}
运行结果
大家感情兴趣,可以多看看官网https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/statements/lock
最后
以上就是大胆太阳为你收集整理的C# lock 语句的全部内容,希望文章能够帮你解决C# lock 语句所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复