简介 
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个 JVM 中,该对象只有一个实例存在。这样的模式有几个好处:
单例模式的优点: 
由于单例模式只生产一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决 
单例模式可以在系统设置全局的访问点,优化环境共享资源访问,例如可以设计一个单例类,负责所以数据表的映射处理 
 
常见的五种单例模式实现方式 :
主要:
饿汉式(线程安全,调用效率高;但是,不能延迟加载) 
懒汉式(线程安全,调用效率不高;但是,可以延迟加载) 
 
 
其他:
双重检测锁式(由于 JVM 底层内部模型原因,偶尔会出问题,不建议使用) 
静态内部类式(线程安全,调用效率高;但是,可以延时加载) 
枚举单例(线程安全,调用效率高,不能延时加载) 
 
 
 
饿汉式 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24  * @ProjectName :  * @Package :        com.example.gof23.creational_patterns.singleton  * @ClassName :      SingletonHg  * @Description :    饿汉式单例模式(Hungry)  * @Author :         Mr.Vincent  * @CreateDate :     2019 /8 /4  23 :33   * @Version :        1.0 .0   */ public  class  SingletonHungry                private  static  SingletonHungry instance = new  SingletonHungry();          private  SingletonHungry ()       }          public  static  SingletonHungry getInstance ()           return  instance;     } } 
懒汉式 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26  * @ProjectName :  * @Package :        com.example.gof23.creational_patterns.singleton  * @ClassName :      SingletonLazy  * @Description :    懒汉式单例模式(Lazy)  * @Author :         Mr.Vincent  * @CreateDate :     2019 /8 /4  23 :44   * @Version :        1.0 .0   */ public  class  SingletonLazy           private  static  SingletonLazy instance;          private  SingletonLazy ()       }          public  static  synchronized  SingletonLazy getInstance ()           if  (instance == null ) {             instance = new  SingletonLazy();         }         return  instance;     } } 
双重检测锁式 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30  * @ProjectName :  * @Package :        com.example.gof23.creational_patterns.singleton  * @ClassName :      SingletonDC  * @Description :    双重检测锁式单例模式(Double Checked Locking)  * @Author :         Mr.Vincent  * @CreateDate :     2019 /8 /5  0 :14   * @Version :        1.0 .0   */ public  class  SingletonDC           private  volatile  static  SingletonDC instance;          private  SingletonDC ()       }          public  SingletonDC getInstance ()           if  (instance == null ) {             synchronized  (SingletonDC.class) {                 if  (instance == null ) {                     instance = new  SingletonDC();                 }             }         }         return  instance;     } } 
静态内部类式 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23  * @ProjectName :  * @Package :        com.example.gof23.creational_patterns.singleton  * @ClassName :      SingletonSIC  * @Description :    静态内部类式单例模式(Static Inner Class)  * @Author :         Mr.Vincent  * @CreateDate :     2019 /8 /5  0 :28   * @Version :        1.0 .0   */ public  class  SingletonSIC      private  static  class  SingletonClassInstance           private  static  final  SingletonSIC instance = new  SingletonSIC();     }          private  SingletonSIC ()       }     public  static  SingletonSIC getInstance ()          return  SingletonClassInstance.instance;     } } 
枚举单例 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19  * @ProjectName :  * @Package :        com.example.gof23.creational_patterns.singleton  * @ClassName :      SingletonEnum  * @Description :    枚举类单例模式(Enum)  * @Author :         Mr.Vincent  * @CreateDate :     2019 /8 /5  0 :40   * @Version :        1.0 .0   */ public  enum  SingletonEnum           INSTANCE;          public  void  singletonOperation ()       } } 
测试 
测试单例模式: 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public  class  Client      public  static  void  main (String[] args)                    SingletonHungry hungry1 = SingletonHungry.getInstance();         SingletonHungry hungry2 = SingletonHungry.getInstance();         System.out.println(hungry1);         System.out.println(hungry2);                  SingletonLazy lazy1 = SingletonLazy.getInstance();         SingletonLazy lazy2 = SingletonLazy.getInstance();         System.out.println(lazy1);         System.out.println(lazy2);                  SingletonDC dc1 = SingletonDC.getInstance();         SingletonDC dc2 = SingletonDC.getInstance();         System.out.println(dc1);         System.out.println(dc2);                  SingletonSIC sic1 = SingletonSIC.getInstance();         SingletonSIC sic2 = SingletonSIC.getInstance();         System.out.println(sic1);         System.out.println(sic2);                  SingletonEnum anEnum1 = SingletonEnum.INSTANCE;         SingletonEnum anEnum2 = SingletonEnum.INSTANCE;         System.out.println(anEnum1==anEnum2);     } } 
结果为:
1 2 3 4 5 6 7 8 9 饿汉式:com.example .gof23 .creational_patterns .singleton .SingletonHungry@1540 e19d 饿汉式:com.example .gof23 .creational_patterns .singleton .SingletonHungry@1540 e19d 懒汉式:com.example .gof23 .creational_patterns .singleton .SingletonLazy@677327 b6 懒汉式:com.example .gof23 .creational_patterns .singleton .SingletonLazy@677327 b6 双重检测锁:com.example .gof23 .creational_patterns .singleton .SingletonDC@14 ae5a5 双重检测锁:com.example .gof23 .creational_patterns .singleton .SingletonDC@14 ae5a5 静态内部类:com.example .gof23 .creational_patterns .singleton .SingletonSIC@7 f31245a 静态内部类:com.example .gof23 .creational_patterns .singleton .SingletonSIC@7 f31245a 枚举单例:true 
测试五种单例模式在多线程环境下的效率 
(关注相对值即可,不同的环境下测试值完全不一样)
五种单例模式 
时间 
 
 
饿汉式(SingletonHungry) 
26ms 
 
懒汉式(SingletonLazy) 
186ms 
 
双重检测锁式(SingletonDC) 
40ms 
 
静态内部类式(SingletonSIC) 
31ms 
 
枚举单例(SingletonEnum) 
37ms 
 
 
CountDownLatch
同步辅助类,在完全一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待 
countDown():当前线程调用此方法,则计数减一(建议放在 finally 里执行)await():调用此方法会一直阻塞当前线程,直到计时器的值为0 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public  class  ClientTimes      public  static  void  main (String[] args)  throws  InterruptedException          long  start = System.currentTimeMillis();         int  threadNum = 10 ;         final  CountDownLatch countDownLatch = new  CountDownLatch(threadNum);         for  (int  i = 0 ; i < threadNum; i++) {             new  Thread(new  Runnable() {                 public  void  run ()                       for  (int  i = 0 ; i < 1000000 ; i++) {                                                  SingletonHungry hungry = SingletonHungry.getInstance();                     }                     countDownLatch.countDown();                 }             }).start();         }                  countDownLatch.await();         long  end = System.currentTimeMillis();         System.out.println("总耗时:"  + (end - start));     } } 
测试结果如上表格
问题(拓展) 
反射可以破解上面几种(不包含枚举式)实现反式(可以在构造方法中手动抛出异常控制) 
反序列化可以破解上面几种(不包含枚举式)实现方式(可以通过定义 readResolver() 防止获得不同的对象)
反序列化时,如果对象所在的类定义了 readResolver(),(实际是一种回调),定义返回那个对象 
 
 
 
例:反射破解单例模式 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package  com.example.gof23.creational_patterns.singleton.expand;public  class  SingletonDemo      private  static  SingletonDemo instance = new  SingletonDemo();          private  SingletonDemo ()       }     public  static  SingletonDemo getInstance ()           return  instance;     } } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public  class  Test_reflect      public  static  void  main (String[] args)  throws  Exception                   Class<SingletonDemo> clazz = (Class<SingletonDemo>) Class.forName("com.example.gof23.creational_patterns.singleton.expand.SingletonDemo" );         Constructor<SingletonDemo> c = clazz.getDeclaredConstructor(null );         c.setAccessible(true );         SingletonDemo sd1 = c.newInstance();         SingletonDemo sd2 = c.newInstance();         System.out.println(sd1);         System.out.println(sd2);     } } 
结果为:
1 2 com.example .gof23 .creational_patterns .singleton .expand .SingletonDemo@1540 e19d com.example .gof23 .creational_patterns .singleton .expand .SingletonDemo@677327 b6 
防止反射破解单例模式:在构造方法中手动抛出异常控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package  com.example.gof23.creational_patterns.singleton.expand;public  class  SingletonDemo      private  static  SingletonDemo instance = new  SingletonDemo();          private  SingletonDemo ()                    if  (instance != null ) {             throw  new  RuntimeException();         }     }     public  static  SingletonDemo getInstance ()           return  instance;     } } 
再运行的结果为:
1 2 com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@135fbaa4 com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@135fbaa4 
例:反序列化破解单例模式 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package  com.example.gof23.creational_patterns.singleton.expand;import  java.io.Serializable;public  class  SingletonDemo  implements  Serializable      private  static  SingletonDemo instance = new  SingletonDemo();          private  SingletonDemo ()       }     public  static  SingletonDemo getInstance ()           return  instance;     } } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public  class  Test_serializable      public  static  void  main (String[] args)  throws  Exception                   SingletonDemo instance1 = SingletonDemo.getInstance();         FileOutputStream fos = new  FileOutputStream("e:/a.txt" );         ObjectOutputStream oos = new  ObjectOutputStream(fos);         oos.writeObject(instance1);         FileInputStream fis = new  FileInputStream("e:/a.txt" );         ObjectInputStream ois = new  ObjectInputStream(fis);         SingletonDemo instance2 = (SingletonDemo) ois.readObject();         System.out.println(instance1);         System.out.println(instance2);     } } 
结果为:
1 2 com.example .gof23 .creational_patterns .singleton .expand .SingletonDemo@135 fbaa4 com.example .gof23 .creational_patterns .singleton .expand .SingletonDemo@58372 a00 
防止反序列化破解单例模式:通过定义 readResolver() 防止获得不同的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package  com.example.gof23.creational_patterns.singleton.expand;import  java.io.Serializable;public  class  SingletonDemo  implements  Serializable      private  static  SingletonDemo instance = new  SingletonDemo();          private  SingletonDemo ()                    if  (instance != null ) {             throw  new  RuntimeException();         }     }     public  static  SingletonDemo getInstance ()           return  instance;     }          private  Object readResolve ()           return  instance;     } } 
再运行结果为:
1 2 com.example .gof23 .creational_patterns .singleton .expand .SingletonDemo@135 fbaa4 com.example .gof23 .creational_patterns .singleton .expand .SingletonDemo@135 fbaa4 
总结:如何用 
单例对象占用资源少,不需要延迟加载:
 
单例对象占用资源大,需要延迟加载:
 
 
参考源码:https://github.com/V-Vincen/GOF23 
        
  
    
      If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !