使用场景:在容器中一个对象只存在一个实例。
目的:1.防止堆中内存过多。影响效率。
2.无论怎么使用,都规定使用同一个对象
实例:获取序列号,任务管理器,计数器等
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
代码:
1.饿汉式(线程安全,调用效率高,但是不能延时加载,会占用内存)
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
2.懒汉式(线程安全,调用效率不高,但是能延时加载)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3.双检锁/双重校验锁 延时加载 比较复杂 不建议使用
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
4.静态内部类 延时加载 只适用于静态域的情况
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
5.枚举 非延时加载
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
一般情况下,建议使用饿汉模式,只有在要明确实现 lazy loading 效果时,才会使用第静态内部类方式。如果涉及到反序列化创建对象时,可以尝试使用枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式。