设计模式之单例模式最佳实现方式 (2)

使用该类的时候才初始化该类

//代码实现
public class LazyMan {

   private LazyMan(){}

   private static LazyMan lazyMan;
   
   public static LazyMan getInstance(){
       if (lazyMan == null){
           lazyMan = new LazyMan();
      }
       return lazyMan;
  }
}

在多线程下使用饿汉式单例,8个线程可能有多个线程能使用该类的构造方法,说明懒汉式单例是线程不安全的

public class LazyMan {

   private LazyMan(){
       System.out.println("懒汉式单例 " + Thread.currentThread().getName());
  }

   private static LazyMan lazyMan;
   
   public static LazyMan getInstance(){
       if (lazyMan == null){
           lazyMan = new LazyMan();
      }
       return lazyMan;
  }

   public static void main(String[] args) {
       for (int i = 0; i <9 ; i++) {
           new Thread(()->{
               LazyMan.getInstance();
          }).start();
      }
  }
}

/*
输出结果:
懒汉式单例 Thread-0
懒汉式单例 Thread-2
懒汉式单例 Thread-1
*/

优点

节省内存空间

缺点:

线程不安全

3、DCL懒汉式(双重检查懒汉式)

解决懒汉式线程不安全的问题

//代码实现
public class DCLLazyMan {

   private DCLLazyMan(){}

   /*
   volatile:
  在原子性上来说是不安全的:
new DCLLazyMan(),创建对象的实例会分解成以下3个指令
•1、分配内存空间
•2、执行构造方法,初始化对象
•3、对象指向内存空间
我们期望按1 2 3 的顺序依次完成,但是在内存中会出现指令重排的过程:
假设A类new DCLLazyMan(),是先分配内存空间、占用此空间、初始化对象,也就是132的顺序执行,
同时另一个线程中的B类也在new DCLLazyMan(),此时A还没有完成DCLLazyMan的构造,就会出现不 安全的问题。

必须加上volatile关键字!
   */
   private volatile static DCLLazyMan lazyMan;

   public static DCLLazyMan getInstance(){
       //第一重检查
       if (lazyMan == null){
           //加锁
           synchronized (DCLLazyMan.class){
               //第二重检查
               if (lazyMan == null){
                   lazyMan = new DCLLazyMan();
              }
          }
      }
       return lazyMan;
  }
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjjjp.html