C# 对象分配是线程安全的吗?

C# 对象分配是线程安全的吗?,c#,multithreading,thread-safety,C#,Multithreading,Thread Safety,这个线安全吗?具体来说,GetMyObject()方法是否可以返回null?我知道两个线程可能会获得不同的MyObject实例,但我不在乎这一点我只想确保安全地假设GetMyObject()永远不会返回null。 class Foo { private static MyObject obj; public static MyObject GetMyObject() { MyObject o = obj; if

这个线安全吗?具体来说,
GetMyObject()
方法是否可以返回null?我知道两个线程可能会获得不同的
MyObject
实例,但我不在乎这一点我只想确保安全地假设
GetMyObject()
永远不会返回null。

   class Foo {
        private static MyObject obj;
        public static MyObject GetMyObject() {
            MyObject o = obj;
            if(o == null) {
                o = new MyObject();
                obj = o;
            }
            return o;
        }
        public static void ClearMyObject() {
            obj = null;
        }
    }

    class MyObject {}

GetMyObject()永远不能返回null。要了解这一点,最简单的方法是注意“o”是一个局部变量,因此没有其他人可以影响它。

好吧,让我们通过以下方式进行推理:

public static MyObject GetMyObject() {
        MyObject o = obj;
        if(o == null) {
            o = new MyObject();
            obj = o;
        }
        return o;
}

只有一个
return
语句。此方法可以生成
null
返回值的唯一方法是,如果唯一的
return
语句
returno
在执行时
o==null
true

当执行
returno
时,如果
o
null
,这意味着我们以
o
null
走出
If
块。当测试
if
块的条件时,我们可以用
o
作为
null
走出
o
块的唯一方法是if
o==null
true
(如果
o==null
false
,那么
o!=null
为true,并且由于
o
是一个局部变量,它不能受任何其他线程的影响。但是
o==null
true
意味着我们最终进入
if
块,现在当构造函数调用
o=new MyObject()
返回,我们保证
o
不为
null
if
块中的第二条语句,
obj=o
,不会影响
o
的值。同样,由于
o
是一个局部变量,因此,如果有多个线程通过此代码路径运行,则无关紧要:每个线程都有其own
o
并且没有其他线程可以接触任何其他线程的
o

因此,无论
o==null
true
还是
false
,当
if
块完成时,
o==null
都是
false

因此,该方法保证返回非空值

我只是想确保安全地假设GetMyObject()永远不会返回null

好吧,如果这就是你所关心的,那就好了。但让我们澄清一点。你的方法不是线程安全的。完全有可能构造两个
MyObject
实例,两个不同的调用方可能最终看到不同的返回值,尽管很明显你的意图是只有一个。要解决这个问题,请s、 我建议只使用
Lazy

私有静态惰性对象;
静态Foo(){
obj=新的懒惰者(
()=>新的MyObject(),
真的
);
}
公共静态MyObject GetMyObject(){
返回对象值;
}
公共静态无效ClearMyObject(){
obj=新的懒惰者(
()=>新的MyObject(),
真的
);
}

它不会返回null,但绝大多数公认的定义都认为它不是线程安全的。您可能希望将对象存储到共享状态,并让其他线程访问该状态。在这种情况下,其他线程可能会创建自己的副本(如您所说)并尝试存储它们,但不能保证所有线程都能看到该对象的最新版本(或该对象的任何其他线程版本)。同样,您的
ClearMyObject()

改用
Lazy
,它将提供您想要的东西

public static readonly Lazy myObject=new Lazy(()=>new myObject(),true);

这个线安全吗

没有

GetMyObject()方法是否可能返回null

没有


该方法保证永远不会返回null。所有读写都保证是原子的。但是,线程不保证读取最新版本的静态字段obj,线程也不保证对obj的更改顺序有一致的看法。任意多个线程可能会争用并观察不同的值Obj.我不认为这个代码是线程安全的,但是也许你对“线程安全”有不同的定义。这是问这个问题的问题;没有一个每个人都可靠地同意的术语的标准定义。< / P>在这个答案的扩展上,“线程安全”意味着“在多线程程序中正确工作”。。问题是,您需要了解整个程序,以及正确工作意味着什么,才能知道有哪些线程安全要求。我不同意这个答案。符合ECMA的编译器可能会消除局部变量,然后如果ClearMyObject()的话,GetMyObject()可能会返回null在正确的时间执行。或者是否有任何官方规范淘汰了原始ECMA规范的内存模型?这个答案是危险的。它是正确的,但它完全忽略了线程安全问题。它取决于所需的语义。这不会泄漏内存,因此从这个角度来看是安全的。它将允许超过要创建一个对象,因此从这个角度来看是不安全的。我发现此模式对于需要单个对象以提高性能的情况非常有用,但如果创建了多个对象实例,则代码将起作用。此代码避免了任何同步开销。很抱歉,性能与此无关。这永远不会成为系统中的瓶颈任何实际应用。
private static Lazy<MyObject> obj;

static Foo() {
    obj = new Lazy<MyObject>(
        () => new MyObject(),
        true
    );
}

public static MyObject GetMyObject() {
    return obj.Value;
}

public static void ClearMyObject() {
    obj = new Lazy<MyObject>(
        () => new MyObject(), 
        true
    );
}