GOF23设计模式之单例模式(singleton)

Posted C3Stones

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GOF23设计模式之单例模式(singleton)相关的知识,希望对你有一定的参考价值。

一、单例模式概述

  保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。

二、单例模式的五种写法

  1.饿汉式

    优点:线程安全,效率高

    缺点:无法延时加载

 1 public class Singleton {
 2     
 3     private static Singleton instance = new Singleton();
 4     
 5     //私有化构造器
 6     private Singleton() {}
 7 
 8     //提供全局访问点
 9     public static Singleton getInstance() {
10         return instance;
11     }
12     
13 }
 1 public class Singleton {
 2     
 3     private static Singleton instance = null;
 4     
 5     static {
 6         instance = new Singleton();
 7     }
 8     
 9     //私有化构造器
10     private Singleton() {}
11 
12     //提供全局访问点
13     public static Singleton getInstance() {
14         return instance;
15     }
16     
17 }

  2. 懒汉式

    优点:线程安全,延时加载

    缺点:效率较低

    (1)非线程安全

 1 public class Singleton {
 2     
 3     private static Singleton instance;
 4     
 5     //私有化构造器
 6     private Singleton() {}
 7 
 8     //提供一个全局的访问点
 9     public static Singleton getInstance() {
10         if (instance == null) {
11             instance = new Singleton();
12         }
13         return instance;
14     }
15     
16 }

    (2)线程安全

 1 public class Singleton {
 2     
 3     private static Singleton instance;
 4     
 5     //私有化构造器
 6     private Singleton() {}
 7 
 8     //使用同步方法获取该类对象
 9     public static synchronized Singleton getInstance() {
10         if (instance == null) {
11             instance = new Singleton();
12         }
13         return instance;
14     }
15     
16 }
 1 public class Singleton {
 2     
 3     private static Singleton instance;
 4     
 5     //私有化构造器
 6     private Singleton() {}
 7 
 8     //使用同步块获取该类对象
 9     public static Singleton getInstance() {
10         synchronized (Singleton.class) {
11             if (instance == null) {
12                 instance = new Singleton();
13             }
14             return instance;
15         }
16     }
17     
18 }

  3.双重检查锁

    注意:由于编译器优化和JVM底层内部模型原因,偶尔会出问题,不建议使用

    优点:线程安全,延时加载

    缺点:效率较低,会出错误

 1 public class Singleton {
 2     
 3     private static Singleton instance;
 4     
 5     private Singleton() {}
 6     
 7     //第一次判断是为了避免不必要的同步,第二次判断是属性为null时创建实例
 8     public static Singleton getInstance() {
 9         if (instance == null) {
10             synchronized (Singleton.class) {
11                 if (instance == null) {
12                     instance = new Singleton();
13                 }
14             }
15         }
16         return instance;
17     }
18 
19 }

  4.静态内部类式

    不调用静态方法不加载内部类,延缓加载(懒加载),提高效率

    优点:线程安全,延时加载,效率高

 1 public class Singleton {
 2     
 3     //静态内部类
 4     private static class SingletonHolder {
 5         //final可加可不加,因为外部类的外部无法使用该内部类
 6         private static /*final*/ Singleton instance = new Singleton();
 7     }
 8     
 9     //私有化构造器
10     private Singleton() {}
11 
12     //提供一个全局的访问点
13     public static Singleton getInstance() {
14         return SingletonHolder.instance;
15     }
16     
17 }

  5.枚举

    注意:建议使用

    优点:实现简单,线程安全,效率高,由于JVM从根本上实现保障,避免反射和反序列化的漏洞

    缺点:无延时加载

1 1 public enum Singleton {
2 2     //这个枚举元素,本身就是一个单例对象
3 3     INSTANCE;
4 4 }

三、破解单例模式 

  1.使用反序列化破解单例对象

 1 import java.io.ObjectStreamException;
 2 import java.io.Serializable;
 3 
 4 /**
 5  * 使用反序列化破解单例模式
 6  * @author 曹磊
 7  *
 8  */
 9 public class Singleton implements Serializable {
10     
11     private static Singleton instance;
12     
13     private Singleton() {}
14 
15     //使用同步方法获取该类对象
16     public static synchronized Singleton getInstance() {
17         if (instance == null) {
18             instance = new Singleton();
19         }
20         return instance;
21     }
22     
23     //反序列化时,如果创建了readResolve()方法则直接返回已经创建好的对象,而不需要再重新创建新的对象
24     private Object readResolve() throws ObjectStreamException {
25         return instance;
26     }
27     
28 }
 1 import java.io.FileInputStream;
 2 import java.io.FileOutputStream;
 3 import java.io.ObjectInputStream;
 4 import java.io.ObjectOutputStream;
 5 
 6 /**
 7  * 测试反序列化破解单例模式
 8  * @author 曹磊
 9  *
10  */
11 public class TestSingleton {
12     
13     public static void main(String[] args) throws Exception {
14         //先获得一个对象
15         Singleton s01 = Singleton.getInstance();
16         System.out.println("先获取的对象:" + s01);
17         
18         //(1)使用序列化将对象写出到系统文件
19         String filePath = "C:\\file\\obj.txt";
20         ObjectOutputStream oos = new ObjectOutputStream(
21                 new FileOutputStream(filePath));
22         oos.writeObject(s01);
23         oos.flush();
24         oos.close();
25         
26         //(2)使用反序列化读取文件中的对象
27         ObjectInputStream ois = new ObjectInputStream(
28                 new FileInputStream(filePath));
29         Singleton s02 = (Singleton) ois.readObject();
30         ois.close();
31         
32         System.out.println("反序列化读取的对象:" + s02);
33     }
34 
35 }

  控制台输出:

先获取的对象:[email protected]
反序列化读取的对象:[email protected]

以上是关于GOF23设计模式之单例模式(singleton)的主要内容,如果未能解决你的问题,请参考以下文章

Java设计模式GOF之单例模式

GoF 23 种设计模式之单例模式

GOF23设计模式之单例模式

GOF23设计模式之单例模式

最全23种设计模式之单例模式(Singleton)

二十三种设计模式(GOF23)详解1----单例模式(Singleton Pattern)