lock 语句获取给定对象的互斥锁,执行语句块,然后释放锁。当锁被持有时,持有该锁的线程可以再次获取并释放该锁。任何其他线程都被阻止获取锁并等待,直到锁被释放。lock 语句确保在任何时刻最多只有一个线程执行它的线程体。
lock 语句采用以下形式:
lock ( x )
{
// 你的代码……
}
变量 x 是 System . Threading . Lock 类型或引用类型的表达式。当 x 在编译时已知为 System . Threading . Lock 类型时,它精确地等价于:
using ( x . IW ( ) )
{
// 你的代码……
}
由 Lock . IW ( ) 返回的对象是一个包含 Dispose ( ) 方法的重构。生成的 using 语句确保释放范围,即使在 lock 语句的主体中抛出异常。
否则,lock 语句就完全等价于:
object _dx锁定 = x;
bool _解锁 = false;
try
{
System . Threading . Monitor . Enter ( _dx锁定 , ref _解锁 );
// 你的代码……
}
finally
{
if ( _解锁 ) System . Threading . Monitor . Exit ( _dx锁定 );
}
由于代码使用了 try……finally…… 语句,因此即使在锁语句体中抛出异常,也会释放锁。
不能在锁语句体中使用 await 表达式。由于代码使用了 try……finally…… 语句,因此即使在锁语句体中抛出异常,也会释放锁。
不能在锁语句体中使用 await 表达式。
导引
从 .NET 9 和 C# 13 开始,锁定 System . Threading . Lock 类型的专用对象实例以获得最佳性能。此外,如果已知的 Lock 对象被强制转换为另一种类型并被锁定,编译器会发出警告。如果使用旧版本的 .NET 和 C#,锁定不用于其他目的的专用对象实例。避免对不同的共享资源使用相同的锁对象实例,因为这可能导致死锁或锁争用。特别要避免使用以下实例作为锁对象:
- 因为调用者也可能锁定这个
- type 实例,因为它们可以通过 typeof 操作符或反射获得
- string 实例,包括 string 字面量,因为它们可能被拘禁
- 保持锁的时间尽可能短,以减少锁争用
例子
下面的示例定义了一个 Account 类,该类通过锁定专用的 balanceLock 实例来同步对其私有 balance 字段的访问。使用相同的锁定实例确保两个不同的线程不能通过同时调用 Debit 或 Credit 方法来更新 balance 字段。示例使用 C# 13 和新的 Lock 对象。如果您使用的是旧版本的 C# 或旧版本的 .NET 库,请锁定 object 的实例。
public class 账户
{
// 在 C# 13 之前使用的“对象”
private readonly System . Threading . Lock _锁定利率 = new ( );
private decimal _利率;
public 账户 ( decimal 初始化利率 ) => _利率 = 初始化利率;
public decimal 借款 ( decimal 金额 )
{
if ( 金额 < 0 )
{
throw new ArgumentOutOfRangeException ( nameof ( 金额 ) , "借款金额不能是负数。" );
}
decimal 实际借款 = 0;
lock ( _锁定利率 )
{
if ( _利率 >= 金额 )
{
_利率 -= 金额;
实际借款 = 金额;
}
}
return 实际借款;
}
public void 贷款 ( decimal 贷款 )
{
if ( 贷款 < 0 )
{
throw new ArgumentOutOfRangeException ( nameof ( 贷款 ) , "贷款金额不能是负数。" );
}
lock ( _锁定利率 )
{
_利率 += 贷款;
}
}
public decimal 获取存款 ( )
{
lock ( _锁定利率 )
{
return _利率;
}
}
}
class Lei账户测试
{
static async Task Main ( )
{
var 新账户 = new 账户( 1000 );
var rws = new Task [ 100 ];
for ( int i = 0 ; i < rws . Length ; i++ )
{
rws [ i ] = Task . Run ( ( ) => Update ( 新账户 ) );
}
await Task . WhenAll ( rws );
Console . WriteLine ( $"账户的存款:{新账户 . 获取存款 ( )}" );
// 输出:
// 账户的存款:2000
}
static void Update ( 账户 account )
{
decimal [ ] 本金s = [ 0 , 2 , -3 , 6 , -2 , -1 , 8 , -5 , 11 , -6 ];
foreach ( var 本金 in 本金s )
{
if ( 本金 >= 0 )
{
account . 贷款 ( 本金 );
}
else
{
account . 借款 ( Math . Abs ( 本金 ) );
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。