我有这堂课:
class MyFoo
{
private static readonly string _foo = InitFoo();
public static string Foo
{
get
{
return _foo;
}
}
private static string InitFoo()
{
Debug.WriteLine("InitFoo");
// do some job
return "Foo";
}
}
私有静态_foo
成员仅在引用MyFoo.Foo
时初始化一次。
从InitFoo()
返回的数据很大,方法可能很耗时(最多1-2秒),我的问题是,当一个线程引用MyFoo.Foo
时,有可能引用它的另一个线程将返回未完成或未初始化的数据b / c InitFoo()
尚未完成?
换句话说,上面的线程安全吗?如果不是如何使其线程安全(如果可能的话避免锁定对象?)
感谢。
编辑:关于Lazy<T>
的评论是否现在更适合线程安全?:
public sealed class MyFoo
{
// Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
static MyFoo() { }
private static readonly Lazy<string> _foo = InitFoo();
public static string Foo
{
get
{
return _foo.Value;
}
}
private static Lazy<string> InitFoo()
{
string s = "Foo";
return new Lazy<string>(() => s);
}
}
答案 0 :(得分:2)
当一个线程引用MyFoo.Foo时,是否有可能引用它的另一个线程将返回未完成或未初始化的数据b / c,InitFoo()还没有完成?
没有。类型初始化是线程安全的:
如果相同的线程初始化MyFoo
在完成MyFoo._foo
之前完成,那么就会有一个问题。初始化,这将导致问题。如果在循环中有相互依赖的类型进行初始化,那么诊断尤为尴尬。
这是一个例子,有两个类型的初始值设定项,每个都使用另一个的值。它们都具有静态构造函数,以使行为具有确定性。 (初始化类型的规则取决于它们是否具有静态构造函数。)
using System;
public class Program
{
public static void Main(string[] args)
{
// Determine which type to initialize first based on whether there
// are any command line arguemnts.
if (args.Length > 0)
{
Class2.DoNothing();
}
Console.WriteLine($"Class1.Value1: {Class1.Value1}");
Console.WriteLine($"Class2.Value2: {Class2.Value2}");
}
}
public class Class1
{
public static readonly string Value1 =
$"When initializing Class1.Value1, Class2.Value2={Class2.Value2}";
static Class1() {}
}
public class Class2
{
public static readonly string Value2 =
$"When initializing Class2.Value2, Class2.Value2={Class1.Value1}";
static Class2() {}
public static void DoNothing() {}
}
在没有任何命令行参数的情况下运行此命令,Class1
首先开始初始化,然后初始化Class2
:
Class1.Value1: When initializing Class1.Value1, Class2.Value2=When initializing Class2.Value2, Class2.Value2=
Class2.Value2: When initializing Class2.Value2, Class2.Value2=
使用任何命令行参数,我们首先初始化Class2
,然后初始化Class1
:
Class1.Value1: When initializing Class1.Value1, Class2.Value2=
Class2.Value2: When initializing Class2.Value2, Class2.Value2=When initializing Class1.Value1, Class2.Value2=