我有一个班级:
class PrintStringDataBuilder
{
PrintStringDataBuilder() { }
public static GetInstance()
{
return new PrintStringDataBuilder();
}
//other class methods and fields, properties
}
从客户代码访问:
PrintStringDataBuilder instance = PrintStringDataBuilder.GetInstance();
以上是线程安全的吗?
编辑:试图避免写作 PrintStringDataBuilder builder = new PrintStringDataBuilder();在asp.net mvc web app中多次。 PrintStringDataBuilder类中没有其他静态方法,静态字段或静态属性。
答案 0 :(得分:11)
是?在不知道该类的构造函数的内部结构的情况下,您可以说调用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;
}
答案 1 :(得分:5)
通过'threadsafe',您是否担心调用静态方法的多个线程将获得SAME PrintStringDataBuilder?答案是否定的,并且调用是线程安全的。
话虽如此,没有人能从你给出的小片段中判断出其余的是否是它的构造函数。类实例不是线程安全的原因有很多。如果他们在没有锁定的情况下引用静态属性就是一个例子。
答案 2 :(得分:3)
输入方法始终是线程安全的。访问共享数据可能不是。所以这段代码是线程安全的,因为没有共享数据。
如果您的目的是为所有线程设置一个PrintStringDataBuilder
实例,那么为此目的,您的代码将无效。你需要适当的单身人士。在.NET 4中,代码可以非常紧凑:
private static Lazy<PrintStringDataBuilder> instance = new Lazy<PrintStringDataBuilder>();
public static PrintStringDataBuilder Instance
{
get { return instance.Value; }
}
这将保证在每个线程中PrintStringDataBuilder.Instance
将指向将以惰性方式创建的PrintStringDataBuilder
对象的相同且仅一个实例,即仅在首次使用时才会创建
答案 3 :(得分:1)
@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。使用Interlocked.Exchange和双重检查锁:
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;
}
希望这有帮助。