lock 關鍵字將語句塊標記爲臨界區,方法是獲取給定對象的互斥鎖,執行語句,而後釋放該鎖。安全
lock語句根本使用的就是Monitor.Enter和Monitor.Exit,也就是說lock(this)時執行Monitor.Enter(this),大括號結束時執行Monitor.Exit(this).他的意義在於什麼呢,對於任何一個對象來講,他在內存中的第一部分放置的是全部方法的地址,第二部分放着一個索引,他指向CLR中的SyncBlock Cache區域中的一個SyncBlock.什麼意思呢?就是說,當你執行Monitor.Enter(Object)時,若是object的索引值爲負數,就從SyncBlock Cache中選區一個SyncBlock,將其地址放在object的索引中。這樣就完成了以object爲標誌的鎖定,其餘的線程想再次進行Monitor.Enter(object)操做,將得到object爲正數的索引,而後就等待。直到索引變爲負數,即線程使用Monitor.Exit(object)將索引變爲負數。多線程
使用lock須要注意的地方:less
1.lock不能鎖定空值某一對象能夠指向Null,但Null是不須要被釋放的。(請參考:認識全面的null) 2.lock不能鎖定string類型,雖然它也是引用類型的。由於字符串類型被CLR「暫留」dom
這意味着整個程序中任何給定字符串都只有一個實例,就是這同一個對象表示了全部運行的應用程序域的全部線程中的該文本。所以,只要在應用程序進程中的任何位置處具備相同內容的字符串上放置了鎖,就將鎖定應用程序中該字符串的全部實例。所以,最好鎖定不會被暫留的私有或受保護成員。 3.lock鎖定的對象是一個程序塊的內存邊界 4.值類型不能被lock,由於前文標紅字的「對象被釋放」,值類型不是引用類型的this
5.lock就避免鎖定public 類型或不受程序控制的對象。 例如,若是該實例能夠被公開訪問,則 lock(this) 可能會有問題,由於不受控制的代碼也可能會鎖定該對象。這可能致使死鎖,即兩個或更多個線程等待釋放同一對象。出於一樣的緣由,鎖定公共數據類型(相比於對象)也可能致使問題。 使用lock(this)的時候,類的成員變量的值可能會被不在臨界區的方法改值了spa
應用場景:常常會應用於防止多線程操做致使公用變量值出現不肯定的異常,用於確保操做的安全性線程
示例:對象
// statements_lock2.cs using System;索引
using System.Threading;進程
class Account {
private Object thisLock = new Object();
int balance;
Random r = new Random();
public Account(int initial)
{
balance = initial;
}
int Withdraw(int amount)
{
// This condition will never be true unless the lock statement
// is commented out:
if (balance < 0)
{
throw new Exception("Negative Balance");
}
// Comment out the next line to see the effect of leaving out
// the lock keyword:
lock(thisLock)
{
if (balance >= amount)
{
Console.WriteLine("Balance before Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw : -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after Withdrawal : " + balance);
return amount;
}
else
{
return 0;
// transaction rejected
}
}
}
public void DoTransactions()
{
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
}
}
class Test {
static void Main()
{
Thread[] threads = new Thread[10];
Account acc = new Account(1000);
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(acc.DoTransactions));
threads[i] = t;
}
for (int i = 0; i < 10; i++)
{
threads[i].Start();
}
}
}