NET面试题:C#中的lock关键字有何作用
更多.net面試題,.net電子書,.net教學視頻請參考"51CTO提醒您,請勿濫發廣告!"
NET面試題:C#中的lock關鍵字有何作用
作為C#的程序員來說,在遇到線程同步的需求時最常用的就是lock關鍵字。但如何正確并有效地使用lock卻是能否高效地達到同步要求的關鍵。正因為如此,程序員需要完全理解lock究竟為程序做了什么。
??所涉及的知識點
· lock的等效代碼
· System.Threading.Monitor類型的作用和使用方法
??分析問題
1.lock的等效代碼
在.NET的多線程程序中,經常會遇到lock關鍵字來控制同步,比如下列代碼:
private object o = new object();
public void Work()
{
lock(o)
{
??//做一些需要線程同步的工作
}
}
事實上,lock這個關鍵字是C#為方便程序員而定義的語法,它等效于安全地使用System.Threading.Monitor類型。上面的代碼就直接等效于下面的代碼:
private object o = new object();
public void Work()
{
//這里很重要,是為了避免直接使用私有成員o,而導致線程不安全
Object temp = o;
System.Threading.Monitor.Enter(temp);
try
{
??//做一些需要線程同步的工作
}
finally
{
??System.Threading.Monitor.Exit(temp);
}
}
正如讀者所看到的,真正實現了線程同步功能的,就是System.Threading.Monitor類型,lock關鍵字只是用來代替調用Enter、Exit方法,并且將所有的工作包含在try塊內以保證其最終退出同步。
2.System.Threading.Monitor類型的作用和使用
在前文中筆者已經提到了,Monitor類型的Enter和Exit方法用來實現進入和退出對象的同步。具體來說,當Enter方法被調用時,對象的同步索引將被檢查,并且.NET將負責一系列的后續工作來保證對象訪問時線程的同步,而Exit方法的調用,則保證了當前線程釋放該對象的同步塊。
代碼7-13演示了如何利用lock關鍵字(也就是Monitor類型)來實現線程同步,具體定義了一個包含需要同步執行方法的類型。
代碼7-13??線程同步:UseLock.cs
? ? /// <summary>
? ? /// 演示同步鎖
? ? /// </summary>
? ? public class Lock
? ? {
? ?? ???//用來在靜態方法中同步
? ?? ???private static Object o1 = new object();
? ?? ???//用來在成員方法中不同
? ?? ???private Object o2 = new object();
? ?? ???//成員變量
? ?? ???private static int i1 = 0;
? ?? ???private int i2 = 0;
? ?? ???/// <summary>
? ?? ???/// 測試靜態方法的同步
? ?? ???/// </summary>
? ?? ???/// <param name="state">狀態對象</param>
? ?? ???public static void Increment1(Object state)
? ?? ???{
? ?? ?? ?? ?lock (o1)
? ?? ?? ?? ?{
? ?? ?? ?? ?? ? Console.WriteLine("i1的值為:{0}", i1.ToString());
? ?? ?? ?? ?? ? //這里刻意制造線程并行機會
? ?? ?? ?? ?? ? //來檢查同步的功能
? ?? ?? ?? ?? ? Thread.Sleep(200);
? ?? ?? ?? ?? ? i1++;
? ?? ?? ?? ?? ? Console.WriteLine("i1自增后為:{0}", i1.ToString());
? ?? ?? ?? ?}
? ?? ???}
? ?? ???/// <summary>
? ?? ???/// 測試成員方法的同步
? ?? ???/// </summary>
? ?? ???/// <param name="state">狀態對象</param>
? ?? ???public void Increment2(Object state)
? ?? ???{
? ?? ?? ?? ?lock (o2)
? ?? ?? ?? ?{
? ?? ?? ?? ?? ? Console.WriteLine("i2的值為:{0}", i2.ToString());
? ?? ?? ?? ?? ? //這里刻意制造線程并行機會
? ?? ?? ?? ?? ? //來檢查同步的功能
? ?? ?? ?? ?? ? Thread.Sleep(200);
? ?? ?? ?? ?? ? i2++;
? ?? ?? ?? ?? ? Console.WriteLine("i2自增后為:{0}", i2.ToString());
? ?? ?? ?? ?}
? ?? ???}? ?? ?
? ? }
這樣,在main方法中調用該類型對象的方法和其靜態方法,測試其同步的效果,如代碼7-14所示。
代碼7-14??線程同步:UseLock.cs
/// <summary>
/// 程序入口
/// </summary>
class MainClass
{
? ? /// <summary>
? ? /// 測試同步效果
? ? /// </summary>
? ? static void Main(string[] args)
? ? {
? ?? ???//開始多線程
? ?? ???Console.WriteLine("開始測試靜態方法的同步");
? ?? ???for (int i = 0; i < 5; i++)
? ?? ???{
? ?? ?? ?? ?Thread t = new Thread(Lock.Increment1);
? ?? ?? ?? ?t.Start();
? ?? ???}
? ?? ???//這里等待線程執行結束
? ?? ???Thread.Sleep(5*1000);
? ?? ???Console.WriteLine("開始測試成員方法的同步");
? ?? ???Lock l = new Lock();
? ?? ???//開始多線程
? ?? ???for (int i = 0; i < 5; i++)
? ?? ???{
? ?? ?? ?? ?Thread t = new Thread(l.Increment2);
? ?? ?? ?? ?t.Start();
? ?? ???}
? ?? ???Console.Read();
? ? }
}
下面是程序的執行結果:
開始測試靜態方法的同步
i1的值為:0
i1自增后為:1
i1的值為:1
i1自增后為:2
i1的值為:2
i1自增后為:3
i1的值為:3
i1自增后為:4
i1的值為:4
i1自增后為:5
開始測試成員方法的同步
i2的值為:0
i2自增后為:1
i2的值為:1
i2自增后為:2
i2的值為:2
i2自增后為:3
i2的值為:3
i2自增后為:4
i2的值為:4
i2自增后為:5
可以看到,線程同步被很好地保證了。這里需要強調的是,線程同步本身違反了多線程并行運行的原則,所以讀者在使用線程同步時應該盡量做到把lock加在最小的程序塊上。如果一個方法有大量的代碼需要線程同步,那就需要重新考慮程序的設計了,是否真的有必要進行多線程處理,畢竟線程本身的開銷也是相當大的。
對靜態方法的同步,一般采用靜態私有的引用成員,而對成員方法的同步,一般采用私有的引用成員。讀者需要注意靜態和非靜態成員的使用和把同步對象申明為私有,這都是保證線程同步高效并且正確的關鍵點。
??答案
C#中的lock關鍵字實質是調用Monitor.Enter和Monitor.Exit兩個方法的簡化語法,功能上其實現了進入和退出某個對象的同步。在通常情況下,可以通過lock一個私有的引用成員變量來完成成員方法內的線程同步,而通過lock一個私有的靜態引用成員變量來完成靜態方法內的線程同步
轉載于:https://www.cnblogs.com/mingyongcheng/archive/2011/03/27/1996716.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的NET面试题:C#中的lock关键字有何作用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Asp.Net性能优化.
- 下一篇: 怎么在泰山上体验不同的登山路线?