- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例
- 单例类必须给其他对象提供这一实例
懒汉式
线程不安全方式
public class Singleton{private static Singleton instance;private Singleton(){}public static Singleton getInstance(){if(instance == null){instance = new Singleton();}return instance;}}
线程安全方式
在方法上增加 synchronized 修饰。
public class Singleton {private static Singleton instance;private Singleton(){}public static synchronized Singleton getInstance(){if(instance == null){instance = new Singleton();}return instance;}}
饿汉式 - 推荐
类加载时直接创建实例。
public class Singleton {private static Singleton instance = new Singleton();private Singleton(){}private static Singleton getInstance(){return instance;}}
双重校验锁(DCL, Double Checked Locking) - 推荐
public class Singleton{private static Singleton instance;private Singleton(){}private static Singleton getInstance(){if(instance == null){synchronized(Singleton.class){if(instance == null){instance = new Singleton();}}}return instance;}}
静态内部类/登记式
public class Singleton{private Singleton(){}public static Singleton getInstance(){return SingletonInner.INSTANCE;}private static class SingletonInner{public static final Singleton INSTANCE = new Singleton();}}
枚举 - 推荐
这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
不能通过 reflection attack 来调用私有构造方法。
public enum Singleton{INSTANCE;}
总结
一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式。
