1、利用synchronize关键字
public class Singleton {
private static Singleton uniqueInstance;
public static synchronize Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
缺点:会降低性能,同步一个方法可能造成程序执行效率下降100倍。
2、迫切的创建实例,哪怕你用不到它,而不是用延迟实例化
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
public static Singleton getInstance() {
return uniqueInstance;
}
}
缺点:对新建一个用不到的对象也无所谓。
3、使用双重加锁(double-checked locking),保证getInstacne()只在第一次会使用同步
public class Singleton {
private volatile static Singleton uniqueInstance;
public static Singleton getInstance() {
if (uniqueInstacne == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
volatile关键子确保当uniqueInstance变量被初始化成Singleton实例时,多个线程正确的处理uniqueInstance变量(volatile保证了共享变量的可见性,一个线程对变量的操作其他线程会立马知晓,所以不会出现还未初始化完成就被使用的情况)
缺点:Java 1.4中许多JVM虚拟机对于volatile关键字的实现会导致双重检查加锁失败,所以只能使用Java5或以上的版本
tips:有个要注意的地方,关于类加载器的,因为每个类加载器都定义了一个命名空间,如果有两个以上的类加载器,不同的类加载器可能会加载同一个类,从整个程序来看,同一个类会被加载多次。如果这样的事情发生在单件上,就会产生多个单件并存的怪异现象,所以,如果你的程序有多个类加载器同时又使用了单件模式,请格外小心。有一个解决办法:自行指定类加载器,并指定同一个类加载器。
tips2:在Java 1.2之前,垃圾收集器有个bug:当单件在没有全局引用时会被当做垃圾被清除,也就是说,如果一个单件只有本单件类引用它本身,那么该单件就会被当做垃圾清除。这造成让人困惑的bug,因为在单件被清除之后,下次调用getInstance()会产生一个“全新的”单件。对很多程序来说,这会造成让人困惑的行为,因为对象的实例变量值都不见了,一切回到原始的设置(例如:网络连接被重新设置)。但是在Java 1.2以后,这个bug已经被修正了,也不再需要一个全局引用来保护单件。