當多個執行緒可以呼叫單一物件的屬性與方法時,這些呼叫必須同步。 否則一個執行緒可能會中斷另一個執行緒正在做的事,導致物件處於無效狀態。 其成員不受此類中斷影響的類別,稱為執行緒安全。
.NET 提供多種策略來同步存取實例與靜態成員:
同步的程式碼區域。 你可以利用 Monitor 這個類別或編譯器支援,只同步需要同步的程式碼區塊,提升效能。
手動同步。 你可以使用 .NET 類別函式庫提供的同步物件。 請參閱 同步原語概述,其中包含該 Monitor 類別的討論。
同步的情境。 僅適用於 .NET Framework 應用程式,您可以使用 SynchronizationAttribute 為 ContextBoundObject 物件啟用簡單的自動同步。
命名空間中的 System.Collections.Concurrent 集合類別。 這些類別提供內建的同步加減操作。 如需詳細資訊,請參閱 Thread-Safe 集合。
通用語言執行時提供一種執行緒模型,類別可依需求以多種方式同步。 下表顯示對於特定同步類別的欄位與方法所提供的同步支援。
| Category | 全域欄位 | 靜態欄位 | 靜態方法 | 實例欄位 | 實例方法 | 特定代碼區塊 |
|---|---|---|---|---|---|---|
| 沒有同步 | No | No | No | No | No | No |
| 同步情境 | No | No | No | Yes | Yes | No |
| 同步碼區域 | No | No | 僅在已標示時 | No | 僅在已標記時 | 僅在已標記時 |
| 手動同步 | Manual | Manual | Manual | Manual | Manual | Manual |
無同步處理
這是物件的預設設定。 任何執行緒都可以在任何時間存取任何方法或欄位。 一次只能有一個執行緒存取這些物件。
手動同步
.NET 類別函式庫提供多種用於同步執行緒的類別。 請參見 同步原語概述。
同步碼區域
你可以使用 Monitor 類別或編譯器關鍵字來同步程式碼區塊、實例方法和靜態方法。 不支援同步靜態場。
Visual Basic 和 C# 都支援使用特定的語言關鍵字來標記程式碼區塊:在 C# 中是 lock 陳述式,在 Visual Basic 中是 SyncLock 陳述式。 當執行緒執行程式碼時,會嘗試取得該鎖。 如果鎖已被其他執行緒取得,執行緒會阻塞直到鎖可用。 當執行緒退出同步的程式碼區塊時,無論執行緒如何離開區塊,鎖都會被釋放。
Note
在 .NET 9 和 C# 13 或更新版本中,如果lock目標是專用System.Threading.Lock實例,lock該敘述會用Lock.EnterScope()來建立同步區域。
Visual Basic 在 SyncLock 中不支援 System.Threading.Lock,因此請繼續使用 SyncLock,並搭配專用的私有參考型別。
如果 lock 目標不是 Lock 實例,且對所有 SyncLock 使用,編譯器會使用 Monitor.Enter 和 Monitor.Exit。 因為這個實作,你仍然可以在同步區域中使用其他 Monitor 方法。
你也可以為方法加上值為 MethodImplOptions.Synchronized 的 MethodImplAttribute,其效果與使用 Monitor 或其中一個編譯器關鍵字來鎖定整個方法主體相同。
Thread.Interrupt 可用於將執行緒從阻塞操作中解救出來,例如等待存取同步的程式碼區域。 Thread.Interrupt 也用於將執行緒從操作中拆解出來,例如 Thread.Sleep。
Important
不要鎖定型別——也就是typeof(MyType)在 C#、 GetType(MyType) Visual Basic 或 MyType::typeid C++ 中——以保護static方法(SharedVisual Basic 中的方法)。 改用私有靜態物件吧。 同樣地,不要在 C#(thisVisual Basic)中用Me來鎖定實例方法。 改用私有物件。 類別或實例可能被非你自己的程式碼鎖定,可能導致死結或效能問題。
編譯器支援
Visual Basic 和 C# 都支援一個語言關鍵字,該關鍵字會使用 Monitor.Enter 和 Monitor.Exit 來鎖定物件。 Visual Basic 支援 SyncLock 語句;C# 支援 lock 陳述句。
在這兩種情況下,如果程式碼區塊中拋出例外,由 lock 或 SyncLock 取得的鎖定都會自動釋放。 C# 和 Visual Basic 編譯器會產生一個 try/finally 區塊,在 try 的開頭呼叫 Monitor.Enter,並在 finally 區塊中呼叫 Monitor.Exit。 如果在 lock 或 SyncLock 區塊內擲回例外,finally 處理常式就會執行,以便讓你進行任何清理工作。
同步脈絡
僅限於 .NET Framework 應用程式,你可以在任何 ContextBoundObject 上使用 SynchronizationAttribute,以同步所有執行個體方法和欄位。 同一上下文域中的所有物件共用相同的鎖。 允許多個執行緒存取方法與欄位,但同一時間僅允許單一執行緒存取。