我有一节课:
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);
}
}
发布于 2018-05-11 16:51:16
当一个线程引用另一个引用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=
https://stackoverflow.com/questions/50296738
复制相似问题