1. 程式人生 > 其它 >lock與Monitor

lock與Monitor

應用場景

lock 確保當一個執行緒位於程式碼的臨界區時,另一個執行緒不進入臨界區。如果其他執行緒試圖進入鎖定的程式碼,則它將一直等待(即被阻止),直到該物件被釋放。
lock語句根本使用的就是Monitor.EnterMonitor.Exit,也就是說lock(this)時執行Monitor.Enter(this),大括號結束時執行Monitor.Exit(this)。
應用場景:經常會應用於防止多執行緒操作導致公用變數值出現不確定的異常,用於確保操作的安全性,比如搶購。
鎖等於“行為可以預期”,不鎖等於“行為不可預期”。

搶購舉例

假設有商品庫存為10,共有1000名顧客在幾乎同一時間進行搶購。
不加lock的寫法:

Parallel.For(0, customerCount, (i) =>
{
	TryToBuyGoods(customerCount);
});

加lock的寫法:(實際上轉為單執行緒)

Parallel.For(0, customerCount, (i) =>
{
	lock (inStockLock)
	{
		TryToBuyGoods(customerCount);
	}
});

加Monitor的寫法:(實際上轉為單執行緒)

Parallel.For(0, customerCount, (i) =>
{
	bool lockWasTaken = false;
	try
	{
		System.Threading.Monitor.Enter(inStockLock, ref lockWasTaken);
		TryToBuyGoods(customerCount);
	}
	finally
	{
		if (lockWasTaken)
			System.Threading.Monitor.Exit(inStockLock);
	}
});
private void TryToBuyGoods(int customerCount)
{
	var buyCustomer = Customers[random.Next(0, customerCount)];
	var sleepTime = random.Next(1000, 10000);
	if (inStock > 0)
	{
		//模擬購物業務邏輯處理時間(佔用資源)
		Thread.Sleep(sleepTime);
		inStock--;
		//上述流程是先處理一系列業務邏輯,後減庫存,在不加lock的情況下會出現超賣現象
		//建議的邏輯是,先減庫存-處理業務邏輯-後續庫存不足,恢復庫存,並提示使用者“購買失敗”
		Console.WriteLine($"顧客{buyCustomer.Name}購買了一件商品");
	}
	//Console.WriteLine($"當前庫存:{inStock}");
}

結果如下:



可以看出,這種情況不加lock是非常危險的事情。

示例程式碼

UseLockDemo

Monitor的其他用法

private static void WriteToResource(Random rnd, int timeout)
{
    try
    {
        //嘗試獲得鎖
        if(Monitor.TryEnter(locker, timeout))
        {
            resource = rnd.Next(500);
            Display("writes resource value " + resource);
            writes++;
        }
        else
        {
            //獲取失敗
            Display("can not writes resource value.");
        }
    }
    catch
    {

    }
    finally
    {
        //如果獲得了鎖,需要釋放
        if(Monitor.IsEntered(locker))
            Monitor.Exit(locker);
    }
}

示例程式碼

示例程式碼MonitorTestDemo

參考資料

lock 語句(C# 參考)
Monitor 類

學習技術最好的文件就是官方文件,沒有之一。
還有學習資料Microsoft LearnCSharp LearnMy Note
如果,你認為閱讀這篇部落格讓你有些收穫,不妨點選一下右下角的推薦按鈕。
如果,你希望更容易地發現我的新部落格,不妨點選一下關注