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