【发布时间】:2010-09-13 10:17:33
【问题描述】:
关于静态类中的静态变量的问题。
如果我有一个静态类并在其中设置一个属性的值,公开暴露,这个变量的值是否为该类的所有实例设置?那么如果线程 1 将属性的值设置为 999,那么线程 2 的值是否也设置为 999?
【问题讨论】:
关于静态类中的静态变量的问题。
如果我有一个静态类并在其中设置一个属性的值,公开暴露,这个变量的值是否为该类的所有实例设置?那么如果线程 1 将属性的值设置为 999,那么线程 2 的值是否也设置为 999?
【问题讨论】:
是的,是的。 AppDomain 中的静态类字段只有一份副本。
但是,您应该考虑同步。如果线程 1 设置(写入)变量并且线程 2 同时读取它,您可能会得到意想不到的结果,因为一个写入操作实际上可能被划分为多个处理器指令。
假设您设置了long 的值。这是一个 64 位值,写入它涉及至少 2 个处理器指令(在 32 位机器上)。从理论上讲,可能会在两个写入指令之间安排读取相同的long 变量,从而导致意外行为。
【讨论】:
只是为了补充讨论(为什么不呢?):是的,static 属性在类的所有实例之间共享,无论线程如何(除非支持字段标记为ThreadStatic,即!)。但是,是的,在处理此类属性时,您必须面对潜在的多线程问题。这是我认为其他人正在处理的情况。
考虑这段代码:
int x = MyClass.StaticProperty;
MyClass.StaticProperty = x + 1;
前面是一个非常简单的示例,说明竞争条件可能导致两个线程执行假定两个不可分割的操作,但实际上最终成为一个单独的操作。
举例说明:
线程 1 线程 2 int x = MyClass.StaticProperty; // 比方说 int x = MyClass.StaticProperty; // 这是 1。 MyClass.StaticProperty = x + 1; // 好的,所以 x 是 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);
}
}
在更复杂的情况下(即,当您不是简单地以直接的方式修改纯数字字段时),您可能需要设计自己的同步策略,其中最常见的是有一个指定的锁对象,并且简单地lock 用于您想要以原子方式执行的每个操作。
【讨论】: