Skip to main content
 首页 » 编程设计

c#之使用 setter 时,何时应该在多线程单例中锁定静态实例

2024年02月04日37qq号

试图了解何时锁定静态变量被认为是最佳实践。静态实例 setter 是线程安全的吗?如果不是,应该是,为什么(不使其成为线程安全的后果是什么)?

class MyClass 
{ 
    private static MyClass _instance; 
 
    private static readonly object _padlock = new object(); 
 
    public static MyClass Instance 
    { 
        get 
        { 
            if(_instance == null) 
            { 
                lock(_padlock) 
                { 
                    if(_instance == null) 
                    { 
                        _instance = new MyClass(); 
                    } 
                } 
            } 
            return _instance; 
        } 
        set => _instance = value; 
    } 
 
} 

请您参考如下方法:

这称为双重检查锁定。

但是,双重检查锁定要求底层字段是volatile1。

简而言之,分配是原子的,但它需要在不同的核心/CPU 之间同步(完全隔离,通过锁)。原因是另一个核心同时读取该值可能会缓存一个过时的值1。

有几种方法可以使代码线程安全:

  • 避免双重检查锁定,并简单地执行lock 语句中的所有操作。
  • 使用 volatile 关键字使字段volatile。
  • 使用 Lazy 类,保证线程安全。

注意:完全无人看守的二传手进一步增加了复杂性3..

但是,在您的情况下,使用双重检查锁定 可能会在使用 volatile 字段进行一次检查和锁定时正常工作,但我认为您最好的选择是完全锁定一切并保证安全

public static MyClass Instance 
{ 
    get 
    { 
         lock(_padlock) 
         { 
             if(_instance == null) 
                 _instance = new MyClass(); 
             return _instance; 
         } 
 
    } 
    set  
    { 
         lock(_padlock) 
         { 
             _instance = value; 
         } 
    }  
} 

注意:是的,它会导致性能下降


引用


其他资源