静态属性和静态构造函数的相关问题

  有的时候我们可能需要一个静态类来满足某些程序的需要(常见于 ASP.NET 中),而且需要在静态类中初始化一些变量,于是我们有了静态构造函数:
public static class Library
{
    
public static SettingSection GlobalSetting { getprivate set; }    //使用了 C# 3.0 的自动属性

    
static Library()
    {
        GlobalSetting 
= new SettingSection();    //在静态构造函数中初始化静态变量
    }
}

  静态构造函数由 .NET CLR 加载类后(即首次使用该类时)自动调用,因此不能带任何修饰符和参数,而且最多执行一次。大多数应用这样写就可以了,然而,我在 SettingSection 的构造函数中有抛出异常的代码,因此,如果抛出异常的话,会给出 Library 初始化错误的异常,并且以后也都将无法使用 Library 类。

  为了解决这个问题,我们可以在访问属性的时候再初始化:

public static class Library
{
    
public static SettingSection GlobalSetting
    {
        
get
        {
            
if (globalSetting == null)
                globalSetting 
= new SettingSection();
            
return globalSetting;
        }
    }

    
private static SettingSection globalSetting;
}

  乍一看,问题解决了,因为这样的话即使抛出了异常,只是本次调用产生异常,globalSetting 依然保持为 null,我们可以在另外一段程序中保证不抛出异常而正常初始化 GlobalSetting。

  问题真的这么简单么?

  静态类,尤其是在 ASP.NET 中,通常要

被多个线程同时访问的。假如说 2 个线程访问了 GlobalSetting,同时检测到 globalSetting 为 null,同时调用了 new SettingSection,然后赋值给 globalSetting,这会导致初始化这一过程被多次调用。因此我们需要用锁来避免多线程同时调用:

public static class Library
{
    
public static SettingSection GlobalSetting
    {
        
get
        {
            
if (globalSetting == null)
                
lock (lockObject)
                    
if (globalSetting == null)
                        globalSetting 
= new SettingSection();
            
return globalSetting;
        }
    }

    
private static SettingSection globalSetting;
    
private static object lockObject = new object();
}

  这样当 2 个线程同时访问到这里时,系统会让一个较早进入 lock 临界区的线程执行初始化,而另外一个线程则在 lock 临界区等待,待初始化完毕,解除 lock 后,等待的线程进入 lock 区,而经过二次判断后就不再执行初始化,保证了初始化只执行一次。

posted @ 2008-08-13 12:26  田嵩  阅读(441)  评论(1编辑  收藏  举报