每個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
{
lock (typeof(SharedClass))
{
//隨機睡眠一段時間(5秒~10秒)
Thread.Sleep((new Random()).Next(5000, 10000));
SharedClass._counter = value;
}
}
}
但維持原有的頁面存取碼不變:
protectedvoid Page_Load(object sender, EventArgs e)
{
SharedClass.counter++;
Response.Write(SharedClass.counter.ToString());
}
情況會怎樣?請感興趣的朋友試一試,並思索一下出現這種現象的原因。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=2028663