標籤:
一、Lock定義
lock 關鍵字可以用來確保代碼塊完成運行,而不會被其他線程中斷。它可以把一段代碼定義為互斥段(critical section),互斥段在一個時刻內只允許一個線程進入執行,而其他線程必須等待。這是通過在代碼塊運行期間為給定對象擷取互斥鎖來實現的。
在多線程中,每個線程都有自己的資源,但是代碼區是共用的,即每個線程都可以執行相同的函數。這可能帶來的問題就是幾個線程同時執行一個函數,導致資料的混亂,產生不可預料的結果,因此我們必須避免這種情況的發生。
而在.NET中最好瞭解一下進程、應用域和線程的概念,因為Lock是針對線程一級的,而在.NET中應用域是否會對Lock起隔離作用,我的猜想是,即不在同一應用域中的線程無法通過Lock來中斷;另外也最好能瞭解一下資料區段、程式碼片段、堆、棧等概念。
在C# lock關鍵字定義如下:
lock(expression) statement_block,其中expression代表你希望跟蹤的對象,通常是對象引用。
如果你想保護一個類的執行個體,一般地,你可以使用this;如果你想保護一個靜態變數(如互斥程式碼片段在一個靜態方法內部),一般使用類名就可以了。
而statement_block就是互斥段的代碼,這段代碼在一個時刻內只可能被一個線程執行。
二. lock的含義
lock(objectA){codeB} 看似簡單,實際上有三個意思,這對於適當地使用它至關重要:
1. objectA被lock了嗎?沒有則由我來lock,否則一直等待,直至objectA被釋放。
2. lock以後在執行codeB的期間其他線程不能調用codeB,也不能使用objectA。
3. 執行完codeB之後釋放objectA,並且codeB可以被其他線程訪問。
三. lock的使用
public class Singleton
{
private static Singleton _instance = null;
private Singleton(){}
public static Singleton CreateInstance()
{
if(_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
}
上例是定義了一個單例的樣本.
但是上例沒有考慮線程並發擷取執行個體問題,即可能出現兩個線程同時擷取instance執行個體,且此時其為null時,就會出現兩個線程分別建立了instance,違反了單例規則。因此,需對上面代碼修改。
這個時候就可以使用LOCK()
publicclass Singleton
{
privatestatic Singleton instance;
privatestaticobject _lock=newobject();
private Singleton() { }
publicstatic Singleton GetInstance()
{
if(instance==null)
{
lock(_lock)
{
if(instance==null)
{
instance=new Singleton();
}
}
}
return instance;
}
}
上述代碼使用了雙重鎖方式較好地解決了多線程下的單例模式實現。先看內層的if語句塊,使用這個語句塊時,先進行加鎖操作,保證只有一個線程可以訪問該語句塊,進而保證只建立了一個執行個體。再看外層的if語句塊,這使得每個線程欲擷取執行個體時不必每次都得加鎖,因為只有執行個體為空白時(即需要建立一個執行個體),才需加鎖建立,若果已存在一個執行個體,就直接返回該執行個體,節省了效能開銷.
C# 中使用Lock關鍵字