当前位置 主页 > 网站技术 > 代码类 >

    详解JAVA 七种创建单例的方法

    栏目:代码类 时间:2020-01-12 12:07

    1 饿汉式

    public class Singleton1 {
      //不能延迟加载 占用内存 耗费资源
      private static Singleton1 singleton1 = new Singleton1();
    
      public static Singleton1 getSingleton1() {
        return singleton1;
      }
    }
    
    

    可以保证多个线程下唯一实例,getSingleton1 方法性能较高,但是无法进行懒加载。

    2 懒汉式

    public class Singleton2 {
    
      //延迟加载
      // 多线程下 不安全
      private static Singleton2 singleton1 = null;
    
      public Singleton2 getSingleton1() {
    
    
        if (singleton1==null){
          singleton1 = new Singleton2();
        }
        return singleton1;
      }
    }
    
    

    懒汉式 解决了延迟加载和资源问题,但是多线程下存在线程不安全问题。

    3 懒汉式 + 同步

    public class Singleton3 {
    
      //延迟加载
      // 多线程下 不安全
      private static Singleton3 singleton1 = null;
    
      //解决延迟加载 多线程安全问题,但存在读操作,加锁问题,线程排队,写操作只有一次 获取时需要排队等候问题
      public synchronized Singleton3 getSingleton1() {
    
        if (singleton1==null){
          singleton1 = new Singleton3();
        }
        return singleton1;
      }
    
    /*
      等同方法前加锁
      public static Singleton3 getSingleton1() {
        synchronized(Singleton3.class){
          if (singleton1==null){
            singleton1 = new Singleton3();
          }
        }
    
        return singleton1;
      }
      */
    
    
    }
    
    

    解决延迟加载 多线程安全问题,但存在读操作,加锁问题,线程排队,写操作(创建对象)只有一次 ,但是获取时需要排队等候问题

    4 懒汉式 + 双重检验

    public class Singleton4 {
    
      //延迟加载
      private static Singleton4 singleton1 = null;
    
      // 解决 读操作 多线程情况下 排队获取问题, 但是双重校验 也存在一个问题,jvm 重排序的问题下 会存在空指针问题
      public static Singleton4 getSingleton1() {
    
        if (singleton1==null){
          synchronized (Singleton4.class) {
            if (singleton1 == null) {
              singleton1 = new Singleton4();
            }
          }
        }
        return singleton1;
      }
    
    
    }
    
    

    解决 读操作 多线程情况下 排队获取问题, 但是双重校验 也存在一个问题,jvm 重排序的问题下 会存在空指针问题

    但存在一个问题,jvm指令重排序, JVM 的即时编译器中存在指令重排序的优化。

    1 首先给 singleton1 分配内存
    2 Singleton4 执行构造函数 开辟空间
    3 调用getSingleton1()方法创建对象
    JVM 的即时编译器中存在指令重排序的优化

    理想情况下 jvm执行顺序是123 也可能是 132 ,13在创建完对象后 ,再执行2 返回null,此时就是空指针了。

    5 懒汉式 + 双重检验 + volatile

    volatile 关键字 禁止JVM编译时指令重排序

    public class Singleton5 {
    
      //延迟加载
      // volatile 关键字 禁止指令重排序
      // 解决 双重校验 也存在一个问题,jvm 重排序的问题下 会存在空指针问题
      private static volatile Singleton5 singleton1 = null;
    
    
      public static Singleton5 getSingleton1() {
    
        if (singleton1==null){
          synchronized (Singleton5.class) {
            if (singleton1 == null) {
              singleton1 = new Singleton5();
            }
          }
        }
        return singleton1;
      }
    
    
    }