单例模式
单例模式属于创建型模式,一个单例类在任何情况下都只存在一个实例
-
所以构造方法必须是私有的(阻止对象被new出来)
-
由自己创建一个静态变量存储实例
-
只对类进行一次实例化,以后都直接获取第一次实例化的对象
-
对外提供一个静态公有方法获取实例。
优点是内存中只有一个实例,减少了开销,尤其是频繁创建和销毁实例的情况下并且可以避免对资源的多重占用。
缺点是没有抽象层,难以扩展,与单一职责原则冲突。
-
Spring 的 ApplicationContext 创建的 Bean 实例都是单例对象,还有 ServletContext、数据库连接池等也都是单例模式。
-
有饿汉式(直接创建好实例返回),懒汉式(获取对象的时候创建)
-
懒汉式解决方法有:DCL(双重检查加锁,会导致指令重排),静态内部类来创建实例
饿汉式
- 在类加载时就初始化创建单例对象,线程安全,但不管是否使用都创建对象可能会浪费内存。
public class HungrySingleton {
private HungrySingleton(){}
private static HungrySingleton instance = new HungrySingleton();
public static HungrySingleton getInstance() {
return instance;
}
}
懒汉式
- 在外部调用时才会加载,线程不安全,可以加锁保证线程安全但效率低。
public class LazySingleton {
private LazySingleton(){}
private static LazySingleton instance;
public static LazySingleton getInstance() {
if(instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
双重检查锁
- 使用 volatile 以及多重检查来减小锁范围,提升效率。
public class DoubleCheckSingleton {
private DoubleCheckSingleton(){}
private volatile static DoubleCheckSingleton instance;
public static DoubleCheckSingleton getInstance() {
if(instance == null) {
synchronized (DoubleCheckSingleton.class) {
if (instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
静态内部类
- 同时解决饿汉式的内存浪费问题和懒汉式的线程安全问题。
public class StaticSingleton {
private StaticSingleton(){}
public static StaticSingleton getInstance() {
return StaticClass.instance;
}
private static class StaticClass {
private static final StaticSingleton instance = new StaticSingleton();
}
}
枚举
- 《Effective Java》提倡的方式,不仅能避免线程安全问题,还能防止反序列化重新创建新的对象,绝对防止多次实例化,也能防止反射破解单例的问题。
public enum EnumSingleton {
INSTANCE;
}