饿汉式
public class Singleton {
private static String instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
饿汉式以空间换时间。预先创建好实例,不会有线程安全的问题。但是,会浪费内存空间。
懒汉式
public class Singleton {
private static String instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉式以时间换空间,在要使用的时候才实例化对象。但这个版本的饿汉式是存在线程安全问题的。在多线程情况下,推荐使用双检锁。
双检锁
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class) {
if(instance == null) {
instance == new Singleton();
}
}
}
return instance;
}
}
双检锁,也叫双重校验锁(Double Checked Locking, DCL)。解决了线程安全的问题,也比直接上锁提高了执行效率,也节省了空间。
静态内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
外部类加载时,内部类并不会立刻加载。只有当getInstance方法被调用的时候,内部类才会被加载,并且初始化实例。这种方法不仅延迟了实例的加载,而且还保证了单例的唯一性,也能保证线程安全。
枚举实现单例
public enum Singleton {
INSTANCE;
public Singleton getInstance() {
return INSTANCE;
}
}
业内大神Joshua Bloch说过:"单元素的枚举类型已经成为实现Singleton的最佳方法"。原因如下:
- 将构造器私有化并不保险
- 序列化前后对象并不相等,这个不符合单例模式的定义(可以解决)
而枚举实现的单例模式可以避免这些问题。
这篇文章重点在于单例模式的写法,而不是为什么。所以这里只是简单介绍了一下各种写法的优缺点。
对于 单元素的枚举类型已经成为实现Singleton的最佳方法 这句话的理解,我这里就不阐述了,感兴趣的可以自行上网查找。