是否可以使用Hashtable作为锁定对象?

时间:2014-11-23 08:24:55

标签: c# .net multithreading

我有以下代码,其中“_ht”是表示缓存的Hashtable,而“_isLoaded”表示它是否已加载。

我们的系统有许多进程访问“_ht”对象,如果没有加载,我需要它们等待。

使用“_ht”作为锁定对象是错误的吗?我应该为此方案使用专用的对象类型类成员吗?

重要的是要提到这个班级是SINGLETON。

private Hashtable _ht = new Hashtable();
private bool _isLoaded = false;

internal Hashtable GetHT()
        {
            if (_isLoaded == false)
            {
                lock (_ht)
                {
                    if (_isLoaded == false)
                    {
                        LoadHt(_ht);
                    }
                }
            }

            return _ht;
        }

3 个答案:

答案 0 :(得分:10)

您当然可以锁定Hashtable对象,就像您可以在lock语句中使用.NET中的任何引用类型实例一样。但是,它通常被认为是一种较差的方法,主要是因为当一个或多个锁定对象可用于代码的其他部分时,很难跟踪代码如何使用锁定,他们也可能将其用于锁定(再次,不可思议,但你会对人们有时写的代码感到惊讶。

对于一般的锁定,最好使用单独的锁定对象。我会注意到在您的代码示例中,_ht应该是readonly,如果您添加一个单独的锁定对象(例如lockObj),那也应该是只读的。

也就是说,单身场景不应该以这种方式实现。相反,您应该使用CLR自己的静态初始化,或Lazy<T>类:

private static readonly Hashtable _ht = InitializeTable();

internal static Hashtable GetHT() { return _ht; }

private static Hashtable InitializeTable()
{
    Hashtable table = new Hashtable();

    LoadHt(table);

    return table;
}

或者:

private static readonly Lazy<Hashtable> _ht = new Lazy<Hashtable>(() => InitializeTable());

internal static Hashtable GetHT() { return _ht.Value; }

private static Hashtable InitializeTable()
{
    Hashtable table = new Hashtable();

    LoadHt(table);

    return table;
}

当您拥有可能被访问的类型的其他成员时,后者非常有用,但您希望确保哈希表的初始化尽可能延迟(例如,如果可能没有代码实际访问它,所以你可以避免完全初始化它。)

(我将所有内容更改为static,因为您将方案描述为单例,在这种情况下,只有static个成员对代码示例有意义。)

最后我会注意到Hashtable类非常过时。作为一个非泛型类,您真的应该认真考虑升级代码以使用现在已经十年的泛型类型。 Dictionary<TKey, TValue>类是最直接的替代,但人们有时会将Hashtable用作简单集,HashSet<T>数据结构更适合。

答案 1 :(得分:2)

如果您想要来到这里的第一个线程启动它就可以了。但通常你会使用锁定对象。

private Hashtable _ht = new Hashtable();
private bool _isLoaded = false;
private object lockObj = new object();

internal Hashtable GetHT()
{
    if (_isLoaded == false)
    {
         lock (lockObj)
         {
             if (_isLoaded == false)
             {
                 LoadHt(_ht);
             }
         }
     }

     return _ht;
}

答案 2 :(得分:1)

对象本身并未锁定(受保护)。 lock关键字中使用的引用用于标记或标记代码的一部分,该部分不应与使用相同对象引用的任何其他(或相同)代码段同时运行。它实际上并不影响对象本身。 所以答案是您可以在锁定语句中使用现有的HashTable实例。

Best practice虽然是定义要锁定的私有对象,但是私有静态对象变量来保护所有实例共有的数据。

private Object thisLock = new Object();

已编辑感谢@PeterDuniho指出