lock 陳述式 (C# 參考)lock statement (C# Reference)

lock 陳述式會取得指定物件的互斥鎖定、執行陳述式區塊,然後釋放鎖定。The lock statement acquires the mutual-exclusion lock for a given object, executes a statement block, and then releases the lock. 持有鎖定時,持有鎖定的執行緒可以再次取得並釋放鎖定。While a lock is held, the thread that holds the lock can again acquire and release the lock. 其他執行緒將無法取得鎖定,並將等待直到釋放鎖定為止。Any other thread is blocked from acquiring the lock and waits until the lock is released.

lock 陳述式格式為The lock statement is of the form

lock (x)
{
    // Your code...
}

x參考型別的運算式。where x is an expression of a reference type. 其完全等同於It's precisely equivalent to

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 陳述式的主體內擲回例外狀況,也會釋放鎖定。Since the code uses a try...finally block, the lock is released even if an exception is thrown within the body of a lock statement.

您不能在 lock 陳述式主體中使用 await 關鍵字。You can't use the await keyword in the body of a lock statement.

備註Remarks

當您同步處理執行緒對共用資源的存取時,請鎖定專用物件執行個體 (例如 private readonly object balanceLock = new object();) 或另一個不太可能由程式碼不相關的部分用作鎖定物件的執行個體。When you synchronize thread access to a shared resource, lock on a dedicated object instance (for example, private readonly object balanceLock = new object();) or another instance that is unlikely to be used as a lock object by unrelated parts of the code. 避免對不同的共用資源使用相同的鎖定物件執行個體,因為其可能導致鎖死或鎖定爭用。Avoid using the same lock object instance for different shared resources, as it might result in deadlock or lock contention. 尤其要避免使用下列項目當作鎖定物件:In particular, avoid using the following as lock objects:

  • this,呼叫者可能會將其作為鎖定。this, as it might be used by the callers as a lock.
  • Type 執行個體,因為這些可能會由 typeof 運算子或反映取得。Type instances, as those might be obtained by the typeof operator or reflection.
  • 字串執行個體 (包括字串常值),因為那些可能會暫留string instances, including string literals, as those might be interned.

範例Example

下列範例會定義 Account 類別,該類別會透過鎖定專用的 balanceLock 執行個體來同步對其私用 balance 欄位的存取。The following example defines an Account class that synchronizes access to its private balance field by locking on a dedicated balanceLock instance. 使用相同的執行個體進行鎖定,可確保嘗試同時呼叫 DebitCredit 方法的兩個執行緒無法同時更新 balance 欄位。Using the same instance for locking ensures that the balance field cannot be updated simultaneously by two threads attempting to call the Debit or Credit methods simultaneously.

using System;
using System.Threading.Tasks;

public class Account
{
    private readonly object balanceLock = new object();
    private decimal balance;

    public Account(decimal initialBalance)
    {
        balance = initialBalance;
    }

    public decimal Debit(decimal amount)
    {
        lock (balanceLock)
        {
            if (balance >= amount)
            {
                Console.WriteLine($"Balance before debit :{balance, 5}");
                Console.WriteLine($"Amount to remove     :{amount, 5}");
                balance = balance - amount;
                Console.WriteLine($"Balance after debit  :{balance, 5}");
                return amount;
            }
            else
            {
                return 0;
            }
        }
    }

    public void Credit(decimal amount)
    {
        lock (balanceLock)
        {
            Console.WriteLine($"Balance before credit:{balance, 5}");
            Console.WriteLine($"Amount to add        :{amount, 5}");
            balance = balance + amount;
            Console.WriteLine($"Balance after credit :{balance, 5}");
        }
    }
}

class AccountTest
{
    static void Main()
    {
        var account = new Account(1000);
        var tasks = new Task[100];
        for (int i = 0; i < tasks.Length; i++)
        {
            tasks[i] = Task.Run(() => RandomlyUpdate(account));
        }
        Task.WaitAll(tasks);
    }

    static void RandomlyUpdate(Account account)
    {
        var rnd = new Random();
        for (int i = 0; i < 10; i++)
        {
            var amount = rnd.Next(1, 100);
            bool doCredit = rnd.NextDouble() < 0.5;
            if (doCredit)
            {
                account.Credit(amount);
            }
            else
            {
                account.Debit(amount);
            }
        }
    }
}

C# 語言規格C# language specification

如需詳細資訊,請參閱<C# 語言規格>。For more information, see the C# Language Specification. 語言規格是 C# 語法及用法的限定來源。The language specification is the definitive source for C# syntax and usage.

另請參閱See also