如何选用哪种方式实现单例模式?
一般情况下,不建议懒汉式,建议使用饿汉式;只有在要明确实现延迟加载效果时,才会使用静态内部类;如果涉及到反序列化创建对象时,可以尝试使用枚举;如果有其他特殊的需求,可以考虑使用双重检查锁。

  • 3.1 饿汉式
  • 3.2 懒汉式
  • 3.3 double-checked locking(双重检查锁)
  • 3.4 静态内部类
  • 3.5 枚举

延迟加载
线程安全
调用效率

饿汉模式

  1. 1 public class Singleton {
  2. 2 /*
  3. 3 * 利用静态变量来记录Singleton的唯一实例
  4. 4 * 直接初始化静态变量,这样就可以确保线程安全了
  5. 5 */
  6. 6 private static Singleton uniqueInstance = new Singleton();
  7. 7
  8. 8 /*
  9. 9 * 构造器私有化,只有Singleton类内才可以调用构造器
  10. 10 */
  11. 11 private Singleton(){
  12. 12
  13. 13 }
  14. 14
  15. 15 public static Singleton getInstance(){
  16. 16 return uniqueInstance;
  17. 17 }
  18. 18
  19. 19 }

懒汉模式

  1. public class SingletonDemoInLazy {
  2. // 私有实例,初始化的时候不加载(延迟加载)
  3. private static SingletonDemoInLazy instance;
  4. // 私有构造
  5. private SingletonDemoInLazy() {}
  6. // 公共获取实例方法(线程不安全)
  7. public static SingletonDemoInLazy getInstance() {
  8. if(instance == null ) { // 使用的时候加载
  9. instance = new SingletonDemoInLazy();
  10. }
  11. return instance;
  12. }
  13. }

懒汉的双重加锁机制

  1. 1 public class Singleton {
  2. 2 /*
  3. 3 * 利用静态变量来记录Singleton的唯一实例
  4. 4 * volatile 关键字确保:当uniqueInstance变量被初始化成Singleton实例时,
  5. 5 * 多个线程正确地处理uniqueInstance变量
  6. 6 *
  7. 7 */
  8. 8 private volatile static Singleton uniqueInstance;
  9. 9
  10. 10 /*
  11. 11 * 构造器私有化,只有Singleton类内才可以调用构造器
  12. 12 */
  13. 13 private Singleton(){
  14. 14
  15. 15 }
  16. 16
  17. 17 /*
  18. 18 *
  19. 19 * 检查实例,如果不存在,就进入同步区域
  20. 20 */
  21. 21 public static Singleton getInstance(){
  22. 22 if(uniqueInstance == null){
  23. 23 synchronized(Singleton.class){ //进入同步区域
  24. 24 if(uniqueInstance == null){ //在检查一次,如果为null,则创建
  25. 25 uniqueInstance = new Singleton();
  26. 26 }
  27. 27 }
  28. 28 }
  29. 29
  30. 30 return uniqueInstance;
  31. 31 }
  32. 32
  33. 33 }

静态内部类

  1. public class Singleton {
  2. private static class LazyHolder {
  3. private static final Singleton INSTANCE = new Singleton();
  4. }
  5. private Singleton (){}
  6. public static final Singleton getInstance() {
  7. return LazyHolder.INSTANCE;
  8. }
  9. }

枚举模式

  1. public enum Singleton {
  2. INSTANCE;
  3. public void doSomething() {
  4. System.out.println("doSomething");
  5. }
  6. }
  7. 调用方法:
  8. public class Main {
  9. public static void main(String[] args) {
  10. Singleton.INSTANCE.doSomething();
  11. }
  12. }
  13. 直接通过Singleton.INSTANCE.doSomething()的方式调用即可。方便、简洁又安全。

单元素的枚举类型已经成为实现Singleton的最佳方法