首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >使用静态只获取属性线程安全?

使用静态只获取属性线程安全?
EN

Stack Overflow用户
提问于 2018-05-11 16:40:27
回答 1查看 820关注 0票数 2

我有一节课:

代码语言:javascript
代码运行次数:0
运行
复制
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>的评论,现在它对线程安全更好吗?:

代码语言:javascript
代码运行次数:0
运行
复制
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);
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-11 16:51:16

当一个线程引用另一个引用MyFoo.Foo的线程时,它是否有可能得到一个未完成或未初始化的数据返回b/c,InitFoo()还没有完成?

不是的。类型初始化是线程安全的:

  • 在被另一个线程初始化时,没有其他线程可以使用您的类型
  • 初始化线程执行的对内存的所有写入,在执行初始化时对其他线程都是可见的。

有一个缺点是,如果初始化MyFoo的同一个线程在完成初始化之前读取MyFoo._foo,就会产生问题。如果在一个周期中存在相互依赖的初始化类型,那么诊断可能会特别困难。

下面是一个示例,其中有两个类型的初始化器,每个类型都使用另一个类型的值。它们都有静态构造函数,以使行为具有确定性。(类型初始化的规则取决于它们是否具有静态构造函数。)

代码语言:javascript
代码运行次数:0
运行
复制
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

代码语言:javascript
代码运行次数:0
运行
复制
Class1.Value1: When initializing Class1.Value1, Class2.Value2=When initializing Class2.Value2, Class2.Value2=
Class2.Value2: When initializing Class2.Value2, Class2.Value2=

使用任何命令行参数,我们首先初始化Class2,然后再初始化Class1

代码语言:javascript
代码运行次数:0
运行
复制
Class1.Value1: When initializing Class1.Value1, Class2.Value2=
Class2.Value2: When initializing Class2.Value2, Class2.Value2=When initializing Class1.Value1, Class2.Value2=
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50296738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档