这个线程安全吗?具体来说,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 {}
答案 0 :(得分:6)
这个线程安全吗?
没有
GetMyObject()方法是否可以返回null?
没有。
保证该方法永远不会返回null。并且所有的读写都保证是原子的。但是,线程无法保证读取最新版本的静态字段obj ,并且线程无法保证对obj 的更改顺序具有一致的视图。任意多个线程可能会竞争并观察 obj 的不同值。我不认为这个代码“线程安全”,但也许你有一个不同的“线程安全”定义。这是问这个问题的问题;没有标准的术语定义,每个人都可以认可。
答案 1 :(得分:5)
GetMyObject()永远不会返回null。看到这个的简单方法是注意'o'是一个局部变量,所以没有其他人可以影响它。
答案 2 :(得分:4)
好吧,让我们通过这个理由:
public static MyObject GetMyObject() {
MyObject o = obj;
if(o == null) {
o = new MyObject();
obj = o;
}
return o;
}
只有一个return
声明。此方法可以产生null
返回值的唯一方法是,如果唯一的return
语句return o
在执行时o == null
为true
。
如果执行o
时null
为return o
,则表示我们if
阻止了o
null
o
。 o
null
o == null
true
if
o == null
false
o != null
o
o == null
块已经过测试(如果true
是if
,则o = new MyObject()
为真,因为o
是局部变量,所以它不会受到任何其他线程的影响。但是null
1}}为if
意味着我们最终进入obj = o
块内部,现在当构造函数调用o
返回时,我们保证o
不是o
。o
块o == null
中的第二个语句不会影响true
的值。再次,由于false
是局部变量,因此无关紧要通过此代码路径有多个线程:每个线程都有自己的o == null
,没有其他线程可以触及任何其他线程的false
。
因此,无论if
是MyObject
还是Lazy<T>
,当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
);
}
块完成时,我们最终会{{1}}为{{1}}
因此,保证此方法返回非空值。
我只想确保假设GetMyObject()永远不会返回null是安全的。
嗯,如果那就是你关心的那就没关系。但是让我们清楚一些事情。您的方法不是线程安全的。完全有可能构造两个{{1}}实例,并且两个不同的调用者最终可能会看到不同的返回值,即使很明显您的意图只有一个。要解决此问题,我建议您使用{{1}}:
{{1}}
答案 3 :(得分:1)
它不会返回null,但它绝不是大多数公认的定义的线程安全。据推测,您希望将对象存储到共享状态,并让其他线程访问该对象。在这种情况下,其他线程可以创建自己的副本(如您所说)并尝试存储它们,但不保证所有线程都能看到该对象的最新版本(或该对象的任何其他线程版本)。同样,您的ClearMyObject()
方法也不会按照您的想法执行。
使用Lazy<T>
代替您提供所需的内容。
public static readonly Lazy<MyObject> myObject = new Lazy<MyObject>(() => new MyObject(), true);