单例模式:这种模式涉及到一个单一的类,该类自己创建一个且只创建一个自己的对象。这个类提供一种访问其唯一对象的方式,可直接访问,不需要再实例化。
单例模式的几种实现方式:
懒汉式:到用的时候才会实例化。(不推荐使用)
线程不安全:
缺点:多线程不安全,多线程不能正常使用。
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(null == instance) {
instance = new Singleton();
}
return instance;
}
}
线程安全:
优点:多线程安全;第一次调用才初始化,避免内存浪费。
缺点:加synchronized锁,效率低下。
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static synchronized Singleton getInstance() {
if(null == instance) {
instance = new Singleton();
}
return instance;
}
}
饿汉式:类加载时候实例化。(推荐使用)
优点:多线程安全;没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存;容易产生垃圾对象。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() { }
public static Singleton getInstance() {
return instance;
}
}
双检锁/双重校验锁(推荐使用)
优点:多线程安全;第一次调用才初始化,避免内存浪费;双锁机制,多线程保持高性能。
public class Singleton {
private volatile static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(null == instance) {
synchronized (Singleton.class) {
if(null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
登记式/静态内部类(推荐使用)
优点:多线程安全;第一次调用才初始化,避免内存浪费;和双检锁方式效果相同,但实现比双检锁简单。
与饿汉式相比,饿汉式是类加载时就初始化,而该方式是类加载时不会初始化,直到显示调用getInstance()方法时才会初始化。
public class Singleton {
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
private Singleton() { }
public static final Singleton getInstance() {
return SingletonHolder.instance;
}
}
枚举(推荐使用)
优点:简洁,自动支持序列化机制,绝对防止多次实例化。
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
使用场合总结:一般情况下:
- 不建议使用懒汉方式;
- 推荐使用饿汉方式;
- 只有在要明确lazy loading效果时,才会使用登记式/静态内部类方式;
- 如果涉及到序列化创建对象时,可以尝试使用枚举方式;
- 如果有其它特殊需求,可以考虑使用双检锁方式。