是否从静态方法返回引用线程安全
本文关键字:线程 安全 引用 返回 静态方法 是否 | 更新日期: 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 种可能的修改使您的示例真正线程安全:
- 内联初始化静态成员 - 绝对是最简单的!
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;
}
希望这有帮助。