单例设计模式

模式定义:

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

场景:

重量级的对象,不需要多个实例,如线程池,数据库连接池

1、懒汉模式:

延迟加载, 只有在真正使用的时候,才开始实例化
1)线程安全问题
2)double check 加锁优化
3)编译器(JIT),CPU 有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加volatile 关键字进行修饰,对于volatile 修饰的字段,可以防止指令重排
package com.vn.single;

/**
 * @author VN
 */
public class LazySingleton {

  private static volatile LazySingleton instance;

  private LazySingleton() {}

  public static LazySingleton getInstance() {
    if (instance == null) {
      synchronized (LazySingleton.class) {
        if (instance == null) {
          instance = new LazySingleton();
           /*字节码层
           JIT , CPU 有可能对如下指令进行重排序
           1 .分配空间
           2 .初始化
           3 .引用赋值
           如重排序后的结果为如下
           1 .分配空间
           3 .引用赋值 如果在当前指令执行完,有其他线程来获取实例,将拿到尚未初始化好的实例
           2 .初始化*/
        }
      }
    }
    return instance;
  }
}

饿汉模式:

类加载的 初始化阶段就完成了 实例的初始化 。本质上就是借助于jvm类加载机制,保证实例的唯一性(初始化过程只会执行一次)及线程安全(JVM以同步的形式来完成类加载的整个过程)。
类加载过程:
1,加载二进制数据到内存中, 生成对应的Class数据结构,
2,连接: a. 验证, b.准备(给类的静态成员变量赋默认值),c.解析
3,初始化: 给类的静态变量赋初值
只有在真正使用对应的类时,才会触发初始化 如( 当前类是启动类即main函数所在类,直接进行new 操作,访问静态属性、访问静态方法,用反射访问类,初始化一个类的子类等.)
package com.vn.single;

/**
 * @author VN
 */
public class HungrySingleton {

  private static HungrySingleton instance = new HungrySingleton();

  private HungrySingleton() {}

  public static HungrySingleton getInstance() {
    return instance;
  }
}

静态内部类:

1).本质上是利用类的加载机制来保证线程安全
2).只有在实际使用的时候,才会触发类的初始化,所以也是懒加载的一种形式

 

package com.vn.single;

import lombok.extern.slf4j.Slf4j;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * @author VN
 *
 * 静态内部类
 */
@Slf4j
public class InnerClassSingleton implements Serializable {

     private static final long serialVersionUID = 6922639953390195232L;
    public static String name="yyy";
    public static String name1="yyy";
    public static String name2="yyy";

    //  1
    static {
        log.info("InnerClassSingleton");
    }

    private InnerClassSingleton() {

        log.info("InnerClassSingleton--constructor");

        log.info("SingletonHolder.instance:{}",SingletonHolder.instance);

        if (SingletonHolder.instance != null) {
            throw new RuntimeException( " 不允许多个实例" );
        }

    }

    public static InnerClassSingleton getInstance() {
        log.info("InnerClassSingleton--getInstance");
        log.info("SingletonHolder.instance.getInstance:{}",SingletonHolder.instance);
        return SingletonHolder.instance;
    }

    Object readResolve() throws ObjectStreamException {
        log.info("InnerClassSingleton--ObjectStreamException");
        return SingletonHolder.instance;
    }

    /**
     * 静态内部内
     */
    private static class SingletonHolder {

        private static InnerClassSingleton instance=new InnerClassSingleton();

        static {
            // 2
            log.info("SingletonHolder");
        }
    }

}

枚举类型:

1)天然不支持反射创建对应的实例,且有自己的反序列化机制
2)利用类加载机制保证线程安全
package com.vn.single;

import lombok.extern.slf4j.Slf4j;

/**
 * @author VN
 *
 * 枚举类型
 */
@Slf4j
public enum EnumSingleton {
    INSTANCE;

    public void print(){
       log.info("hashCode():{}",hashCode());
    }

}

 

posted @ 2022-05-27 23:21  VNone  阅读(35)  评论(0)    收藏  举报