这个模式应该很常见,在整个程序运行期间只允许该类的一个实例存在,在线程池,缓存,日志对象等都会用到单例模式,简单写个进化史。
经典的单例模式:
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
}
这个写法是线程不安全的,我们来简单分析一下就知道为什么:现在线程1执行到了if (uniqueInstance == null) 停止了交给了线程2,线程2也执行到了if (uniqueInstance == null),不管后面怎么执行,肯定会得到两个实例,这里就会发生莫名其妙的状况。
那怎么办,将getInstance编程synchronized方法,多线程可解决:
public class Singleton {
protected static Singleton uniqueInstance;
// other useful instance variables here
protected Singleton() {}
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// other useful methods here
}
但是又有一个额外的坏处,同步了这个方法以后,程序的性能可能会变得特别差(想想100个线程都在等待使用这个实例,每次都卡这这里排队了),如果实时性要求比较高,那就不能这么做。
有一个方法,可以减少因为同步getInstance方法造成的耗时。首先检查有没有实例存在,然后再以对象为同步锁,而上面的方法是先同步,再检查有没有实例存在最坏的情况,如果100个线程都要同时访问这个实例,那这次是需要排队的,没办法,但是经过这次以后,只需要判断非空就直接返回了,而上面都情况是每次都要排队。
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;
}
}
如果程序总是一只在用单件实例,并且在创建和运行时的耗费对程序来收负担不太重,可以考虑下面的“急切”的方式创建实例:
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}
------------------------------------------------------------------------------------over--------------------------------------------------------------------------------------------------