百天打卡计划第五天-七种单例设计模式的设计

    技术2022-07-11  74

    七种单例设计模式

    饿汉式懒汉式懒汉式 + 同步方法Double-CheckVolatile +Double-CheckHolder 方式枚举方式

    饿汉式

    package day0518; /** * @author liw * @date 2020-07-01 */ public final class Singleton { //实例变量 private byte [] data = new byte[1024] ; //在定义实例变量的时候直接初始化 private static Singleton instance = new Singleton(); //私有构造 private Singleton() { } public static Singleton getInstance(){ return instance ; } }

     饿汉式的关键在于instance 作为类变量并且直接得到了初始化,如果住的的使用了Singleton类难么instance实例将直接完成创建,包括其中的实例变量都会得到初始化,1k的空间的data会被同时创建。

    懒汉式

    package day0518; /** * @author liw * @date 2020-07-01 */ public final class Singleton { //实例变量 private byte[] data = new byte[1024]; //定义实例,但不直接初始化 private static Singleton instance = null; //私有构造 private Singleton() { } public static Singleton getInstance() { if (null == instance) { instance = new Singleton(); } return instance ; } }

     所谓懒汉式就是在使用实例的时候再去创建(用时创建)。但是多线程的情况下是懒汉式是线程不安全的。懒汉式可以保证实例的懒加载,但是无法保证实例的唯一。

    懒汉式 + 同步方法

    package day0518; /** * @author liw * @date 2020-07-01 */ public final class Singleton { //实例变量 private byte[] data = new byte[1024]; //定义实例,但不直接初始化 private static Singleton instance = null; //私有构造 private Singleton() { } //getInstance 方法加入同步控制 public static synchronized Singleton getInstance() { if (null == instance) { instance = new Singleton(); } return instance ; } }

     采用懒汉式+数据同步的方式既满足了懒加载又能百分百的保证instance 实例的唯一性,但是synchronized 关键字天生的排他性导致getInstance 方法只能在同一时刻被一个线程访问,性能低下。

    Double-Check

    package day0518; import java.net.Socket; import java.sql.Connection; /** * @author liw * @date 2020-07-01 */ public final class Singleton { //实例变量 private byte[] data = new byte[1024]; //定义实例,但不直接初始化 private static Singleton instance = null; Connection conn; Socket socket; //私有构造 private Singleton() { //对conn和socket进行初始化 } //getInstance 方法加入同步控制 public static synchronized Singleton getInstance() { if (null == instance) { synchronized (Singleton.class) { if (null == instance) { instance = new Singleton(); } } } return instance; } }

     很聪明的一个方式通过两次校验,第一次判断当instance 为null的时候进入同步代码块,避免每次都需要进入同步代码快;第二次校验instance 为空则为其创建实例。但是这种方式在多线程的情况下有可能会造成空指针异常。有可能在成员变量实例化conn 、socket的发生在instance实例化之后。

    Volatile +Double-Check

    只需要在Double-Check 的模式代码上加个volatile。

    package day0518; import java.net.Socket; import java.sql.Connection; /** * @author liw * @date 2020-07-01 */ public final class Singleton { //实例变量 private byte[] data = new byte[1024]; //定义实例,但不直接初始化 private static volatile Singleton instance = null; Connection conn; Socket socket; //私有构造 private Singleton() { //对conn和socket进行初始化 } //getInstance 方法加入同步控制 public static synchronized Singleton getInstance() { if (null == instance) { synchronized (Singleton.class) { if (null == instance) { instance = new Singleton(); } } } return instance; } }

    Holder 方式

    package day0518; import java.net.Socket; import java.sql.Connection; /** * @author liw * @date 2020-07-01 */ public final class Singleton { //实例变量 private byte[] data = new byte[1024]; //私有构造 private Singleton() { } private static class Holder { private static Singleton instance = new Singleton(); } //getInstance 方法加入同步控制 public static synchronized Singleton getInstance() { return Holder.instance; } }

     Holder方式完全是借助了类的加载的特点。 在Singleton 类中并没有instance 的静态成员,而是将其放到了静态内部类Holder中,因此在Singleton 类的初始化过程中比不过不不会创建Singleton 的实例,Holder 类中定义了Singleton 的静态变量,并且直接进行了实例化,当Holder 被主动使用的时候则会创建Singleton 的实例,Singleton 实例的创建过程在java程序编译时期收集到()方法中,该方法又是同步方法,可以保证内存的可见性、jvm指令的顺序性和原子性。Holder方式的单例是最好的设计之一,也是目前使用比较广的设计。

    枚举方式

    Processed: 0.013, SQL: 9