单例模式顾名思义,就是只有一个实例。
作为对象的创建模式, 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。 单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。
单例类的类图在我的空间相册里面可以看到,即singleton.jpg
显然单例模式的特点有三个:
1.某个类只能有一个实例;
2.它必须自行创建这个实例;
3.它必须自行向整个系统提供这个实例。也就是公开这个类的接口。
对一些类来说,只有一个实例是很重要的。举一个简单的例子:每台计算机可以有若干个打印机,但只能有一台在某一时刻处于工件状态下,以避免两个打印作业同时输出到打印机中而造成打印错误。
下面举几个单例类的写法(假定单例类的类名为Singleton.java):
第一种:
public static Singleton s;
public static Singleton getInstance(){
if(null==s){
s=new Singleton();
}
return s;
}
上述代码不是线程安全的,原因如下:
如果一个线程在到达粗体表示的代码之前发生切换,那么成员变量s仍然是null,然后另一个线程可能接下来进入到if块中,两个不同的单例类的实例就被创建。这样就违背的单例模式的特点。这种情况虽然很少出现,但是一旦出现,这样的错误就很难被人察觉出来。
第二种:
public static Singleton s;
public static Singleton getInstance(){
if(null==s){
synchronized(Singleton.class){
if(null==s){
s=new Singleton();
}
}
}
return s;
}
上面这种方法使用了线程同步的知识,从而保证了线程的安全性。解释如下:
在这个方法里面,如果一个线程进入同步块之后又被切换,另一个线程接着进入if块。当线程一退出同步块时,线程2会重新检查s是否仍然为null。由于线程一设置的s为成员变量,所以线程二的第二次检查失败,第二个单例类实例不会被创建。