单例模式是23种设计模式应用最广的一种,也是最简单的一种设计模式。它确保一个类只有一个实例对象。
实现方式有很多种,具体如下:
一、饿汉式(不使用同步方法)
public class Singleton {
private static Singleton singleton = new Singleton(); // 直接初始化一个实例对象
private Singleton() { // 私有构造方法,保证该类对象不能直接被new出来
}
public static Singleton getInstance() { // 公有静态方法对外提供获取对象实例的途径
return singleton;
}
}
顾名思义,这种方法直接把对象实例 new 出来了,不管该对象是否用到,所以造成了一定程度的资源浪费,不推荐。
二、懒汉式(使用同步方法)
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
这种方法是在需要获取实例的时候才去创建对象,getInstance() 方法加锁,保证了线程安全,但同时由于是对整个对象上锁,所以也造成了性能的下降。
三、双重检测(DCL)
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
作为第二种方法的改进版,DCL 缩小了加锁的粒度,保证线程安全的同时提高了性能。volatile 保证有序性(禁止指令重排序)和可见性。
四、枚举类型
class Resource {
}
enum Singleton {
INSTANCE;
private Resource resource = new Resource();
public Resource getInstance() {
return resource;
}
}
实际上 enum 继承自 Enum 类,而且是 final 的,有且仅有 private 构造方法,每个枚举默认是 static final 的,也就保证了 INSTANCE 只能被实例化一次。 只需要通过调用 Singleton.INSTANCE.getInstance() 方法即可获取实例。
五、静态内部类
public class Singleton {
private Singleton() {
}
private static class Inner {
private static Singleton singleton = new Singleton();
}
public static Singleton getInstance() {
return Inner.singleton;
}
}
采用这种方式,第一次加载 Singleton 类时,并不会实例化单例对象,只有第一次调用 getInstance() 方法时会导致虚拟机加载 Inner 类,这种方式不仅能保证对象的单一性,还避免加锁带来的性能问题,同时使用了延迟加载,保证了线程安全性,所以是实现单例模式的最佳方式。
参考资料
PREVIOUSJava 中父类对象能不能强制转换为子类对象
NEXT八达岭