【问题标题】:C# using Lazy Initialization and lock togetherC# 使用延迟初始化和锁定在一起
【发布时间】:2015-10-20 11:30:48
【问题描述】:

我希望我的一些对象被延迟初始化,例如:

private static Lazy<MappingEngine> engine = new Lazy<MappingEngine>(() =>
{
    return new MappingEngine();
})

而且我不希望多个线程在初始化后访问该对象。我是否也应该使用锁定机制来防止这种情况,或者 Lazy 是否以这种方式支持线程安全?同时使用 Lazy 和 lock 似乎不是正确的做法。

docs 中声明“使延迟对象线程安全并不能保护延迟初始化的对象。如果多个线程可以访问延迟初始化的对象,则必须使其属性和方法对多线程访问安全.

编写一个自定义类型,它是一种惰性类型,并且每次都锁定engine.Value 被称为合乎逻辑的事情吗?举个例子:

public class MyLazyType<T> : Lazy<T>
{
    private object lockObj = new object(); //not static since the reference to this class will be

    public MyLazyType(Func<T> valueFactory) : base(valueFactory)
    {

    }

    public new T Value
    {
        get
        {
            lock (lockObj)
            {
                return base.Value;
            }
        }
    }
}

用法:

private static MyLazyType<MappingEngine> engine = new MyLazyType<MappingEngine>(() =>
{
    return new MappingEngine();
})

【问题讨论】:

    标签: c# multithreading lazy-initialization


    【解决方案1】:

    Lazy&lt;T&gt; 的专业化不会提供额外的好处。突出显示的问题如下:

    var t1 = new Thread(()=>{
        myLazy.Value.SomeNonThreadsafeMethod();
    });
    
    var t2 = new Thread(()=>{
        myLazy.Value.SomeNonThreadsafeMethod();
    });
    
    t1.Start();
    t2.Start();
    

    很明显,在你得到你的值之后,惰性函数在它的操作中不再扮演任何角色,如果要跨多个线程使用这个值,你需要在它的方法和属性中编写额外的保护。

    【讨论】:

    • 如果我们在访问 myLazy.Value 时加了一个锁(就像我在 MyLazyType 中所做的那样),它不会让所有 SomeNonThreadsafeMethod 调用都安全吗?
    • @sotn 不,因为在调用SomeNonThreadsafeMethod 的那一刻,我们已经不在锁的范围内了。
    • 哎呀 :) 不知道我在写那堂课时是怎么想的 :) 实际上我在发布问题时是这么想的。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-18
    • 2020-05-10
    • 1970-01-01
    • 2011-11-17
    • 1970-01-01
    相关资源
    最近更新 更多