定义
单例模式(singleton pattern)确保一个类只有一个实例,并提供一个全局访问点。
代码实现
以下代码是线程安全的,并且是延时实例化的。
public class Singleton {
// volatile:不优化和缓冲sInstance变量,每次某线程修改该值时,对其它的线程都是马上可见的
// static: 静态变量,该类的所有实例共享该变量
// private: 对外不可见,只能通过getInstance方法访问
private volatile static Singleton sInstance;
// 该类不能直接new一个对象,只能通过getInstance方法获得该对象
private Singleton() {}
// 类方法,通过类可直接调用该方法,不用先实例化
public static Singleton getInstance() {
// 还未实例化的,先实例化
// 已经实例化了,直接返回
if (sInstance == null) {
// 线程间同步,只有创建时需要同步
synchronized (Singleton.class) {
// 在临界区内再判断是否为空
if (sInstance == null) {
//真正的实例化
sInstance = new Singleton();
}
}
}
return sInstance;
}
}
注意:
在JDK1.5之前,许多JVM对于volatile关键字的实现会导致上面的例子会失效。JDK1.5及之后的版本可正常使用。
由于上例在JDK1.5之前的版本会失效,这里再给出一种线程安全,类加载时实例化的做法。
public class Singleton {
// JVM在加载该类的时候,马上创建一个实例
// JVM保证在任何线程访问sInstance之前,已经创建了该实例,因此是线程安全的
private static Singleton sInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return sInstance;
}
}
上例的缺点是,加载类时就已经实例化了对象,不能延时实例化对象。
注意:
当有多个类加载器(class loader)时,单例模式可能会失效。因为每个类加载器都定义了一个命名空间,如果有2个以上的类加载器时,不同的类加载器可能会加载同一个类,这样上面的两种实现方式都会失效而产生多个实例。如果你真的遇到了有多个类加载器同时也使用了单例模式,有一个解决办法是,自行指定类加载器,并指定同一个类加载器。
该模式体现了哪些OO原则
目前好像没有引用到什么原则。
本章总结
当你使用多个类加载器,可能会导致单例模式失效而产生多个实例
上面的提到的两个单例模式的实现,可根据情况选择一种