每個ASP.NET應用程式都可以添加一個App_Code檔案夾。放置在這一檔案夾下的類可以被此ASP.NET應用程式中的所有頁面所使用,可将這些類稱為“全局類”,用起來很友善。
然而,如果這些類中定義了靜态成員,則通路這些成員必須小心陷井。
請看以下示例:
public class SharedClass
{
public static int counter=0;
}
上述類放在App_Code中。網頁通路代碼如下:
protectedvoid Page_Load(object sender, EventArgs e)
SharedClass.counter++;
Response.Write(SharedClass.counter.ToString());
上述代碼好象沒有什麼問題,而且實驗運作好象每次都正常。
然而,由于Web應用程式是多線程的,而App_Code中的類具有全局性,是以,上述代碼會帶來一個多線程資料存取沖突的問題。
我們可以修改SharedClass類來使這個問題突出出來:
privatestaticint _counter = 0;
publicstaticint Counter
get {
returnSharedClass._counter;
}
set {
Thread.Sleep((newRandom()).Next(5000, 10000));
SharedClass._counter = value;
上述代碼通過随機延遲時間來以模拟網際網路下的程式并發運作環境。
頁面通路共享資源的代碼不變。
現在請打開多個浏覽器視窗,通路同一個頁面(或多次重新整理),注意通路間隔小于5秒,會發現多個頁面得到相同的數字。事實上,這一數字并沒有真實地反映出共享資源被通路的次數。
為了解決這個問題,可以将頁面代碼修改如下:
protectedvoid Page_Load(object sender, EventArgs e)
lock (typeof(SharedClass))
{
SharedClass.Counter++;
Response.Write("共享資源被通路次數:" + SharedClass.Counter.ToString());
使用C#提供的lock關鍵字鎖定資源現在,問題解決了。
另一個有趣的問題是,如果由共享資源本身實作存取控制,是否通路者就不需要再寫存取控制代碼了?
為此再次修改共享資源類:
public class SharedClass
{
private static int _counter = 0;
public static int Counter
get
lock (typeof(SharedClass))
{
return SharedClass._counter;
}
set
//随機睡眠一段時間(5秒~10秒)
Thread.Sleep((new Random()).Next(5000, 10000));
但維持原有的頁面通路代碼不變: