C#中l(wèi)ock關(guān)鍵字的使用小結(jié)
在C#中,lock
關(guān)鍵字用于確保當(dāng)一個(gè)線程位于給定實(shí)例的代碼塊中時(shí),其他線程無(wú)法訪問(wèn)同一實(shí)例的該代碼塊。這是一種簡(jiǎn)單的同步機(jī)制,用來(lái)防止多個(gè)線程同時(shí)訪問(wèn)共享資源或執(zhí)行需要獨(dú)占訪問(wèn)的代碼段(臨界區(qū)),從而避免競(jìng)態(tài)條件和數(shù)據(jù)不一致問(wèn)題。
使用方式
lock
語(yǔ)句的基本語(yǔ)法如下:
lock (expression) { // 需要同步的代碼塊 }
這里的expression
必須是一個(gè)可以被引用的對(duì)象,通常是一個(gè)私有的、專門用于鎖定目的的對(duì)象。lock
實(shí)際上是對(duì)Monitor.Enter
和Monitor.Exit
方法的封裝,并且它保證了即使在發(fā)生異常的情況下也會(huì)正確釋放鎖。
工作原理
- 當(dāng)一個(gè)線程到達(dá)
lock
語(yǔ)句時(shí),它會(huì)嘗試獲取由expression
指定對(duì)象的鎖。 - 如果鎖是可用的(即沒有其他線程持有該鎖),則該線程獲得鎖并進(jìn)入臨界區(qū)執(zhí)行代碼。
- 如果鎖已經(jīng)被另一個(gè)線程持有,則當(dāng)前線程將被阻塞,直到鎖被釋放。
- 一旦線程完成臨界區(qū)內(nèi)的操作,
lock
確保調(diào)用Monitor.Exit
來(lái)釋放鎖,這樣等待中的其他線程就可以繼續(xù)執(zhí)行。
注意事項(xiàng)
- 唯一性:建議為每個(gè)需要保護(hù)的共享資源使用獨(dú)立的鎖對(duì)象。不要使用公共對(duì)象如
this
或類型本身(typeof(TypeName)
)作為鎖對(duì)象,以避免不必要的鎖競(jìng)爭(zhēng)。 - 不可變性:作為鎖的對(duì)象最好是不可變的(immutable),因?yàn)槿绻i對(duì)象的狀態(tài)可以改變,可能會(huì)導(dǎo)致不確定的行為。
- 引用類型:只能對(duì)引用類型的對(duì)象加鎖。值類型不能用于
lock
,因?yàn)槊看窝b箱都會(huì)創(chuàng)建一個(gè)新的對(duì)象,這將破壞鎖定的目的。 - 性能考慮:雖然
lock
是實(shí)現(xiàn)簡(jiǎn)單同步的有效手段,但過(guò)度使用或不當(dāng)使用可能導(dǎo)致性能瓶頸甚至死鎖。盡量減少鎖的作用范圍,并考慮使用更高級(jí)的并發(fā)工具如ReaderWriterLockSlim
、ConcurrentDictionary
等。 - 避免死鎖:設(shè)計(jì)多線程程序時(shí)要注意避免死鎖,即兩個(gè)或更多的線程互相等待對(duì)方釋放鎖的情況。一種預(yù)防措施是保持一致的鎖獲取順序。
示例代碼
下面是一個(gè)簡(jiǎn)單的例子,演示如何使用lock
來(lái)保護(hù)共享資源:
private readonly object lockObject = new object(); private int counter = 0; public void IncrementCounter() { lock (lockObject) { counter++; } }
在這個(gè)例子中,lockObject
是用來(lái)保護(hù)counter
變量的鎖。通過(guò)這種方式,我們可以確保在同一時(shí)間只有一個(gè)線程能夠修改counter
的值,從而避免競(jìng)態(tài)條件。
為什么不能lock值類型
在C#中,lock
語(yǔ)句要求其參數(shù)必須是一個(gè)引用類型的對(duì)象,而不能是值類型。這是因?yàn)?code>lock機(jī)制依賴于對(duì)象的引用標(biāo)識(shí)來(lái)實(shí)現(xiàn)同步控制,具體來(lái)說(shuō),lock
實(shí)際上是對(duì)指定對(duì)象進(jìn)行加鎖操作,確保同一時(shí)間只有一個(gè)線程能夠執(zhí)行被鎖定保護(hù)的代碼塊。
當(dāng)你嘗試對(duì)一個(gè)值類型使用lock
時(shí),會(huì)發(fā)生以下情況:
- 裝箱(Boxing):由于
lock
只能接受引用類型作為參數(shù),因此如果傳遞了一個(gè)值類型,編譯器會(huì)自動(dòng)對(duì)該值類型進(jìn)行裝箱操作,將其轉(zhuǎn)換為一個(gè)引用類型(即Object類型的一個(gè)實(shí)例)。這意味著每次執(zhí)行lock
時(shí)都會(huì)創(chuàng)建一個(gè)新的對(duì)象。 - 失去鎖定的意義:由于每次裝箱都會(huì)創(chuàng)建一個(gè)新的對(duì)象,即使你多次對(duì)同一個(gè)值類型變量使用
lock
,它們實(shí)際上是在不同的對(duì)象上加鎖。因此,這不會(huì)產(chǎn)生預(yù)期的同步效果,因?yàn)椴煌€程可能會(huì)同時(shí)獲取到“鎖”,導(dǎo)致競(jìng)態(tài)條件的發(fā)生。
例如,下面的代碼試圖對(duì)一個(gè)整型變量進(jìn)行鎖定,但實(shí)際上并不會(huì)按預(yù)期工作:
int number = 0; lock (number) // 編譯錯(cuò)誤:無(wú)法對(duì)值類型使用 lock 語(yǔ)句 { // Do something... }
正確的做法是使用一個(gè)專門的引用類型對(duì)象作為鎖對(duì)象。通常,我們會(huì)定義一個(gè)私有的、只讀的對(duì)象用于鎖定目的,以避免意外的鎖競(jìng)爭(zhēng)和確保鎖定的有效性。例如:
private readonly object lockObject = new object(); int number = 0; lock (lockObject) { number++; }
這樣做的好處是可以確保所有希望同步訪問(wèn)共享資源的線程都在同一個(gè)對(duì)象上等待鎖,從而達(dá)到預(yù)期的同步效果??傊?,為了避免上述問(wèn)題并正確地實(shí)現(xiàn)同步邏輯,應(yīng)始終使用引用類型的對(duì)象作為lock
的目標(biāo)。
到此這篇關(guān)于C#中l(wèi)ock關(guān)鍵字的使用小結(jié)的文章就介紹到這了,更多相關(guān)C# lock關(guān)鍵字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Winform圓形環(huán)繞的Loading動(dòng)畫實(shí)現(xiàn)代碼
這篇文章主要介紹了Winform圓形環(huán)繞的Loading動(dòng)畫實(shí)現(xiàn)代碼,有需要的朋友可以參考一下2014-01-01C#結(jié)合數(shù)據(jù)庫(kù)的數(shù)據(jù)采集器示例
這篇文章主要介紹了C#結(jié)合數(shù)據(jù)庫(kù)的數(shù)據(jù)采集器,功能比較實(shí)用,需要的朋友可以參考下2014-07-07Unity?百度AI實(shí)現(xiàn)Logo商標(biāo)識(shí)別
本文主要介紹了Unity實(shí)現(xiàn)檢測(cè)和識(shí)別圖片中的品牌LOGO信息。即對(duì)于輸入的一張圖片(可正常解碼,且長(zhǎng)寬比適宜),輸出圖片中LOGO的名稱、位置和置信度。需要的可以參考一下2022-01-01WPF仿LiveCharts實(shí)現(xiàn)餅圖的繪制
這篇文章主要介紹了如何利用WPF仿LiveCharts實(shí)現(xiàn)餅圖的繪制,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定幫助,需要的可以參考一下2022-07-07手把手教你如何基于C#制作一個(gè)網(wǎng)址檢測(cè)工具
這篇文章主要給大家介紹了關(guān)于如何基于C#制作一個(gè)網(wǎng)址檢測(cè)工具的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-02-02C#畫筆Pen保存和恢復(fù)圖形對(duì)象的設(shè)置方法
這篇文章主要介紹了C#畫筆Pen保存和恢復(fù)圖形對(duì)象的設(shè)置方法,實(shí)例分析了畫筆的保存save及恢復(fù)屬性Restore的相關(guān)使用技巧,需要的朋友可以參考下2015-06-06C#實(shí)現(xiàn)簡(jiǎn)單的loading提示控件實(shí)例代碼
本文通過(guò)實(shí)例代碼給大家介紹了C#實(shí)現(xiàn)簡(jiǎn)單的loading提示控件功能,代碼非常簡(jiǎn)單,具有參考借鑒價(jià)值,需要的朋友參考下吧2017-09-09