乐趣区

关于设计模式:单例模式

1. 饿汉式

// 饿汉式
public class Singleton {private static Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {return INSTANCE;}
}

2. 懒汉式

public class Singleton {
    private static Singleton INSTANCE;

    private Singleton() {}

    public static Singleton getInstance() {if (INSTANCE == null) {INSTANCE = new Singleton();            
        }
        return INSTANCE;
    }
}

3. 线程平安懒汉式 - 双重查看

public class Singleton {
    private static Singleton INSTANCE;

    private Singleton() {}

    public static Singleton getInstance() {if (INSTANCE == null) {synchronized(Singleton.class) {if (INSTANCE == null) {INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}

4. 双重查看的不足之处

以下三种状况会毁坏双重查看的单例模式: 指令重排序、序列 / 反序列化、反射

4.1 指令重排序

INSTANCE = new Singleton() 语句并非原子操作,分为以下三步:

  1. 调配 Singleton 对象内存空间。
  2. 初始化对象。
  3. 将 INSTANCE 对象援用指向调配的内存空间。

因为指令重排序的问题,以上指令在理论状况可能以 1 -> 3 -> 2 的程序执行。
在多线程的状况下可能呈现:

执行程序 线程 A 线程 B
1 调配 Singleton 对象内存空间
2 将 INSTANCE 对象援用指向调配的内存空间
3 拜访 getInstance() 办法,判断 INSTANCE 对象是否为 null
4 因为 INSTANCE 曾经实现了对象援用指向,因为不为 null,但此时 INSTANCE 还没有实现初始化
5 初始化对象
6 拜访 INSTANCE 援用的对象

解决办法:
应用 volatile 润饰 INSTANCE 对象

public class Singleton {
    private volatile static Singleton INSTANCE;

    private Singleton() {}

    public static Singleton getInstance() {if (INSTANCE == null) {synchronized(Singleton.class) {if (INSTANCE == null) {INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}

4.2 序列 / 反序列化毁坏单例

参考大佬文章:https://segmentfault.com/a/11…

如果想要避免单例被序列 / 反序列化毁坏。就让单例类实现 readResolve() 办法。

public class Singleton {
    private volatile static Singleton INSTANCE;

    private Singleton() {}

    public static Singleton getInstance() {if (INSTANCE == null) {synchronized(Singleton.class) {if (INSTANCE == null) {INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }

    private Object readResolve() {return Singleton.INSTANCE;}
}

4.3 反射毁坏单例

参考大佬文章:https://segmentfault.com/a/11…
为了避免反射毁坏单例,采纳枚举实现单例模式。

public enum EnumSingleton {
    INSTANCE; 
    public EnumSingleton getInstance(){return INSTANCE;}
}

参考文献
https://www.liaoxuefeng.com/w…
https://segmentfault.com/a/11…

退出移动版