是否从静态方法返回引用线程安全

本文关键字:线程 安全 引用 返回 静态方法 是否 | 更新日期: 2023-09-27 18:32:42

我有一个类:

class PrintStringDataBuilder
{
    PrintStringDataBuilder() { }
    public static GetInstance()
    {
        return new PrintStringDataBuilder();
    }
    //other class methods and fields, properties
}

从客户端代码访问为:

PrintStringDataBuilder instance = PrintStringDataBuilder.GetInstance();

上面的调用是线程安全的吗?

编辑:只是试图避免写作PrintStringDataBuilder builder = new PrintStringDataBuilder();在 MVC Web 应用程序中多次 asp.net。类中没有其他静态方法、静态字段或静态属性。

是否从静态方法返回引用线程安全

是吗?在不了解该类构造函数的内部的情况下,您可以说调用GetInstance()是线程安全的。但是,不能保证该实例上的任何方法都是线程安全的,特别是因为您没有提供任何这些方法。

这简称为工厂模式。

编辑:如果您尝试返回单例,则可以这样做:

.NET 4+

private static Lazy<PrintStringDataBuilder> _instance = new Lazy<PrintStringDataBuilder>(() =>
  {
      return new PrintStringDataBuilder();
  });
public static PrintStringDataBuilder GetInstance()
{
    return _instance.Value;
}

.NET 3.5 及更低

版本
private static PrintStringDataBuilder _instance = null;
private static object _lockObject = new object();
public static PrintStringDataBuilder GetInstance()
{
    if(_instance == null)
    {
         lock(_lockObject)
         {
              if(_instance == null)
                 _instance = new PrintStringDataBuilder();
         }
    }
    return _instance;
}

通过"threadsafe",您是否担心调用静态方法的多个线程将获得相同的PrintStringDataBuilder?答案是否定的,并且调用是线程安全的。

话虽如此,没有人能从你给出的小片段中分辨出类的其余部分是,还是它的构造函数。类实例不是线程安全的原因有很多。如果它们引用不带锁定的静态属性就是一个例子。

输入方法始终是线程安全的。访问共享数据可能不是。因此,此代码是线程安全的,因为没有共享数据。

如果您在这里的目的是为所有线程提供一个 PrintStringDataBuilder 实例,那么为此目的,您的代码将不起作用。您需要适当的单例。在 .NET 4 中,代码可以非常紧凑:

private static Lazy<PrintStringDataBuilder> instance = new Lazy<PrintStringDataBuilder>();
public static PrintStringDataBuilder Instance
{
    get { return instance.Value; }
}

这将保证在每个线程中,PrintStringDataBuilder.Instance将指向PrintStringDataBuilder对象的相同且只有一个实例,该实例将以懒惰的方式创建,即仅在首次使用时并且不早

@Tejs,

实际上,在 .NET 中,您不需要使用双重检查锁定机制 - 有更好的解决方法。 但是,如果您选择这样做,则双重检查锁的实现不正确,并且不是真正的线程安全。 编译器可以优化_instance = new PrintStringDataBuilder();的初始化 - 有 3 种可能的修改使您的示例真正线程安全:

  1. 内联初始化静态成员 - 绝对是最简单的!
    private static PrintStringDataBuilder _instance = new PrintStringDataBuilder;
    public static PrintStringDataBuilder GetInstance()
    {
        return _instance;
    }

2 . 使用"volatile"关键字来确保 JIT 不会优化PrintStringDataBuilder的初始化。


private static volatile PrintStringDataBuilder _instance = null;
private static object _lockObject = new object();
public static PrintStringDataBuilder GetInstance()
{
    if(_instance == null)
    {
         lock(_lockObject)
         {
              if(_instance == null)
              {
                 _instance = new PrintStringDataBuilder();
              }
         }
    }
    return _instance;
}

3 .使用带有双重检查锁定的互锁交换:


private static PrintStringDataBuilder _instance = null;
private static object _lockObject = new object();
public static PrintStringDataBuilder GetInstance()
{
    if(_instance == null)
    {
         lock(_lockObject)
         {
              if(_instance == null)
              {
                 var temp = new PrintStringDataBuilder();
                 Interlocked.Exchange(ref _instance, temp);
              }
         }
    }
    return _instance;
}

希望这有帮助。