静态类中的静态属性

8

关于静态类中的静态变量的问题。

如果我有一个静态类并在其中设置了一个公开暴露的属性的值,那么这个变量的值是否对该类的所有实例都设置了?因此,如果线程1将属性的值设置为999,那么线程2的值也会被设置为999吗?

2个回答

14

是的,这是正确的。静态类的字段在一个应用程序域(AppDomain)中只有一份拷贝。

但是您需要考虑同步问题。如果线程1设置(写入)变量,而线程2同时读取它,可能会得到意外的结果,因为一个写操作可能实际上被分成多个处理器指令。

假设您设置了一个long的值。这是一个64位的值,写入它至少涉及两个处理器指令(在32位机器上)。理论上可能读取同一long变量的操作被安排在这两个写操作指令之间,从而导致意外行为。


5
严格来说,静态类没有实例,但每个静态字段有一个单独的副本。 - Marc Gravell
你说得对。感谢提供额外的信息。我已经更新了我的答案。 - Ronald Wildenberg
@Marc:是的,但是...... OP 确实 有点混淆了,“这个变量的值是否设置为类的所有实例?”所以我猜测OP实际上只是有一个普通的类,并且在谈论一个静态属性。要么就是误用了“实例”这个词。 - Dan Tao

2
只是为了增加讨论(为什么不呢?):是的,无论线程如何(除非后备字段标记为 ThreadStatic),static 属性都在类的所有实例之间共享。但是,是的,当处理这些属性时,可能存在潜在的多线程问题。以下是我认为其他人所指的情况。
考虑以下代码:
int x = MyClass.StaticProperty;
MyClass.StaticProperty = x + 1;

上述是竞态条件会导致两个线程执行本应该是不可分割的两个动作,但实际上成为了一个动作的非常简单的例子。
举个例子:
线程1                          线程2
int x = MyClass.StaticProperty;                                 // 假设x是1
                                int x = MyClass.StaticProperty; // 假设x也是1
MyClass.StaticProperty = x + 1;                                 // 那么现在x变成了2
                                MyClass.StaticProperty = x + 1; // 同样写入2
你看出问题了吗?两个线程都可能在任何一个线程写入该属性值之前读取它的值;而被写入的值取决于读取的值,而这两个线程读取到的值是相同的!
在像上面这样的简单场景中,System.Threading命名空间中提供了一个方便的类,可以使多线程读写相对轻松地实现: Interlocked。例如,在线程安全的情况下递增上面的StaticProperty,您可以按照以下方式更新MyClass:
class MyClass
    static int _staticProperty;
    public static int StaticProperty
    {
        get { return _staticProperty; }
    }

    public static int IncrementProperty()
    {
        // increments _staticProperty ATOMICALLY
        // and returns its previous value
        return Interlocked.Increment(_staticProperty);
    }
}

在更复杂的情况下(例如,当您不仅以简单直接的方式修改纯数字字段时),您可能需要设计自己的同步策略,其中最常见的是拥有指定的锁对象,并且对于您想要原子地执行的每个操作,只需在其上加锁。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接