根据单例模式,
public sealed class Singleton
{
static Singleton instance=null;
Singleton()
{
}
public void abc(){
}
public static Singleton Instance
{
get
{
if (instance==null)
{
instance = new Singleton();
}
return instance;
}
}
}上面的代码不是线程安全的,两个不同的线程可能都评估了测试if (instance==null)并发现它是真的,然后都创建了实例,这违反了单例模式。
混淆是实例是静态的,当它在UI线程或其他线程上被调用时,它怎么会是空的?
编辑
我的意思是,一旦我调用了Singleton.Instance.abc();在手动释放Singleton.Instance之前,它不应该为空。对吗?
发布于 2011-12-25 18:44:59
将控制权传递给ThreadA
ThreadA尝试获取Instance,结果发现是null。
将控制权传递给ThreadB
ThreadB尝试获取Instance,结果发现是null。
将控制权传递给ThreadA
ThreadA实例化了Instance。
将控制权传递给ThreadB
ThreadB重新实例化了Instance。
解决方案:你可以使用一个static构造函数来确保这种情况不会发生。
发布于 2011-12-25 18:35:32
你是对的,你显示的单例不是线程安全的。使其线程安全的简单方法是:
public sealed class Singleton
{
static Singleton instance=null;
static lockObject = new object();
Singleton()
{
}
public static Singleton Instance
{
get
{
lock(lockObject)
{
if (instance==null)
{
instance = new Singleton();
}
}
return instance;
}
}
}利用C#使用静态( http://www.yoda.arachsys.com/csharp/singleton.html )的方式,您可以编写一个没有锁的线程安全版本
public sealed class Singleton
{
static readonly Singleton instance=new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton()
{
}
Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
}最后一个版本利用了这样一个事实,即C#中的静态构造函数被指定为仅在创建类的实例或引用静态成员时执行,每个AppDomain执行一次。
发布于 2011-12-25 18:40:15
编辑:
我的意思是,一旦我调用了Singleton.Instance.abc();在手动释放Singleton.Instance之前,它不应该为空。对吗?
一旦单个线程被用来访问单例,它就已经被初始化了,并且在调用之后启动的任何线程都可以安全地访问单例,而不会发生null。
如果你同时启动多个线程来访问Singleton,并且让你的代码保持原样,你就会有一个问题。如果不使用线程同步(lock)来确保每次只输入一个线程的if null块,那么就会出现竞争条件。
如果多个线程偷偷经过if块,那么多个线程将尝试初始化instance。这很混乱,很难说到底会发生什么。一个问题是,您实际上可能会获得多个实例,每个偷偷通过的线程一个实例。任何后续调用(在竞态条件之后)都将获得创建的最后一个实例。
不过,这可能不是您将看到的最糟糕的问题。可能还有更糟糕的问题导致崩溃(不确定)。最好对Singleton使用线程安全操作,而不是找出:)
关于如何让你的Singleton线程安全,请看下面我的原始答案:
您可以在静态构造函数中创建实例。
静态构造函数只会在第一次访问时被调用,因此您不需要惰性初始化代码。
public sealed class Singleton
{
private static Singleton instance;
private Singleton() { }
static Singleton()
{
instance = new Singleton();
}
public static Singleton Instance
{
get { return instance; }
}
}根据the answer to this question的说法,它保证只被调用一次,并且是线程安全的:
在创建类的任何实例或访问任何静态成员之前,保证每个应用程序域只运行一次
静态构造函数。http://msdn.microsoft.com/en-us/library/aa645612.aspx
所示的实现对于初始构造是线程安全的,也就是说,构造Singleton对象不需要锁定或空测试。然而,这并不意味着实例的任何使用都将被同步。有很多种方法可以做到这一点;我已经在下面展示了一种。
https://stackoverflow.com/questions/8629229
复制相似问题