单例模式:顾名思义,即一个应用程序中只需要存在至多一个对象,比如Delphi和Android中的Application对象,为满足这个要求,我们设计如下代码:
public class Singleton {
private static Singleton uniqueInstance;
// other useful instance variables here
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// other useful methods here
}
存在的问题:
但是,上面并不能处理多线程问题,如果现在有两个线程同时在执行getInstance方法,第一个线程刚执行完if (uniqueInstance == null)
还没执行uniqueInstance = new Singleton();
这个时候第二个线程也执行到if (uniqueInstance == null)
,它会发现uniqueInstance
还是null,于是进入到了if判断里面。这样你的单例模式就失败了,因为创建了两个不同的实例。
解决办法
加锁:synchronized,代码如下:
public class Singleton {
private static Singleton uniqueInstance;
// other useful instance variables here
private Singleton() {}
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// other useful methods here
}
存在的问题:
现在虽然解决了多线程导致有可能产生多个实例的情况,但是每次去执行getInstace方法的时候都会受到同步锁的影响,这样运行的效率会降低
解决办法:
将synchronized关键字从方法声明中去除,把它加入到方法体当中,先检查实例是否已经创建,如果尚未创建才进行同步,这样一来,只有第一次才会同步,代码如下:
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
注意:volatile关键字确保,当uniqueInstance变量被初始化成Singleton实例时,多个线程正确地处理uniqueInstance变量