昨天翻了本设计模式的书,发现单例模式竟然有点弄不明白了,抓紧查资料补上,这里总结下。
1:
class Singleton
{
private static Singleton instance;
private Singleton()
{
//
}
public static Singleton getInstance()
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
注意:构造函数私有,方法静态
问题:无法保证线程安全,有多个线程访问getInstance方法的时候可能产生多个Singleton对象。
2:
可以给getInstance方法添加同步:
public static synchronized Singleton getInstance()
{
if (instance == null) //1
instance = new Singleton(); //2
return instance; //3
}
这样能满足需求,但是会带来性能上的损失。一般同步的方法比非同步的方法效率要低上百倍
3:
然后是懒汉式的单例模式:
class Singleton
{
private static Singleton instance = new Singleton();
private Singleton()
{
//
}
public static Singleton getInstance()
{
return instance;
}
}
这种方法能保证instance实例在Singleton类第一次加载的时候初始化,解决了同步问题
进一步的要求可能是不想让instance对象在类加载的时候初始化,而在使用getInstance方法的时候才初始化
4:
双重锁
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
if (instance == null) //2
instance = new Singleton(); //3
}
}
return instance;
}
这种方法能保证instance只被初始化一次。但是由于JVM内部的问题,该方法还是有漏洞的。
假设线程1进入到步骤2,执行步骤3未完成,会先将instance设为非null值。
这时候线程2会在判断instance==null的时候失败,返回一个不完整的intance对象
5:
既要lazy loading,又要同步~
Bob Lee提出了一种方法:
public class Singleton {
private Singleton(){
}
static class SingletonHolder {
static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
在该方法中,Singleton有一个静态内部类,内部类在外部类加载的时候并不会加载,只有在调用getInstance方法的时候加载SingletonHolder类。
如上面的程序还是可能有问题:
Singleton.SingletonHolder sh = new Singleton.SingletonHolder();
Singleton instance = Singleton.SingletonHolder.instance;
instance = sh.instance;
上面的代码是可以访问SingletonHolder的内容的~~
所以进一步的把SingletonHolder设为private的应该会更好。
所以最后的代码如下:
public class Singleton {
private Singleton(){
}
private static class SingletonHolder {
static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
public static void main(String [] args)
{
Singleton.getInstance();
}
}