標籤:lock語句 lock關鍵字 線程同步 鎖對象 lock
在多個線程之間共用資料時,需要考慮線程同步問題,必須確保每次只有一個線程訪問和改變共用資料。
C#中使用lock語句可以輕鬆地設定和解除鎖定以期達到每次只有一個線程訪問和改變共用資料的目的。
下面是一個多線程訪問共用資料的執行個體,看看在沒有進行同步操作的情況下會出現什麼樣的問題?
using System;using System.Threading;namespace LockExamples{ class Program { static int account = 1000;//賬戶 static int pocket = 0;//口袋 static void Main(string[] args) { int threadCount = 10; var threads = new Thread[threadCount]; for (int i = 0; i < threadCount; i++) { threads[i] = new Thread(DoWork); threads[i].Start(); } for (int i = 0; i < threadCount; i++) { threads[i].Join(); } Console.WriteLine("pocket=" + pocket); } public static void DoWork() { if (account >= 1000) { Thread.Sleep(10);//自動取款機打了個小盹 account -= 1000; pocket += 1000; } } } }
可以將範例程式碼理解成:一個使用者分十次從自己的銀行賬戶中取錢。
取錢的邏輯由下面的代碼來實現。
if (account >= 1000){ Thread.Sleep(10);//自動取款機打了個小盹 account -= 1000; pocket += 1000;}
當賬戶中的餘額大於等於1000時,就取出1000放進自己的口袋。
因為使用者當前的賬戶中僅剩下1000,所以就算使用者取了10次,最終口袋中也應該只有1000。那麼實際情況又是怎樣的呢?
請看下面的執行結果(結果也可能是1000,2000,...,9000中的一個)。
結果竟然是10000!!!!!!!!
使用者從僅有1000餘額的賬戶中取出了10000,實在是一件令人振奮人心的事。
不過對於銀行來說,這可不是件什麼好事,因為照這樣下去,銀行的錢遲早會被使用者掏空。
為什麼會出現這樣的結果呢?
這是因為沒有對多線程訪問共用資料進行同步,10個線程同時進入了取錢的邏輯,所以一共取出了10000。
為瞭解決這個問題,可以使用lock語句來同步多線程訪問共用資料。下面是增加lock語句後的取錢邏輯。
private static object o = new object();lock (o){ if (account >= 1000) { Thread.Sleep(10);//自動取款機打了個小盹 account -= 1000; pocket += 1000; }}代碼中使用lock關鍵字鎖定對象o,當一個線程獲得鎖定後,其他線程就無法再獲得鎖定,只有噹噹前線程解除鎖定後,其他對象才可以重新獲得鎖定,這樣一來,就可以保證每次只有一個線程獲得鎖定進而訪問和修改共用資料。
多次執行修改後的範例程式碼,每次都可以得到以下的正確結果。
lock語句鎖定的對象,必須是參考型別。因為鎖定值類型只是鎖定了一個副本,沒什麼意義。
C#多線程開發6:使用lock語句同步多個線程