JAVA设计模式(系列) 单例模式

文章目录

  • 简介
  • 懒汉模式:
  • 饿汉模式:
  • 思考:
    • 通过流获取一个对象实例是否是同一个?
    • 枚举天然支持单例

简介

设计模式的六大原则:
单一原则:一个类或者一个方法只负责一个职责,各个职责的程序改动,不影响其它程序。
里氏代换: 所有引用父类的地方必须能透明地使用其子类的对象,反过来则不成立。
接口隔离: 建立单一接口,不要建立庞大臃肿的接口。一个接口只服务于一个子模块或业务逻辑。
迪米特原则: 一个类对其他的类知道的越少越好,也就是对于被依赖的类的方法和属性尽量私有化。
开闭原则: 对扩展开放,对修改关闭。
依赖倒置: 面向接口编程是依赖倒置原则的核心,上层定义接口,下层实现这个接口, 从而使得下层依赖于上层,降低耦合度。

懒汉模式:

延迟加载,只有在真正使用的时候,才会实例化

  1. 线程安全问题;
  2. double check 加锁优化
  3. 编译器(JIT)CPU有可能会对指令进行重排序,导致使用到尚未初始化的实例,通过volatile关键字修饰
/**
 * 单例模式
 *    懒加载
 *    定义:单例对象的类只能允许一个实例存在
 */
public class LazySingleTon {
    //禁止指令重排
    //使用java中的volatile关键字
    //volatile关键字:保证其他线程对lazySingleTon对象进行创建而未进行初始化的
    //时候,此时CPU分配给这个线程来返回对象(这个对象判断不为空,但还未初始化还是一个空对象)
    public volatile static LazySingleTon lazySingleTon;
    //1:**私有的构造器**
    private LazySingleTon(){
    }
    //2:**提供一个静态方法可供外部调用来返回一个需要的单例对象**
    public static LazySingleTon getLazySingleTon() {
        if(lazySingleTon==null){
            synchronized(LazySingleTon.class){
                //3:**双重检查锁定**
                //并发的时候只在上一个if判断了,另外的线程抢占到锁后在执行创建单例对象的时候需要在校验一次
                // ---双重检查锁定背后的理论是完美的。不幸地是,现实完全不同。
                // ---双重检查锁定的问题是:并不能保证它会在单处理器或多处理器计算机上顺利运行
                if(lazySingleTon==null){
                    lazySingleTon = new LazySingleTon();
                }
            }

        }
        return lazySingleTon;
    }
}

饿汉模式:

类加载的初始化阶段就完成实例的初始化,本质上是借助jvm类的加载机制,保证实例的唯一性

类加载过程:

  • 加载二进制数据到内存中,生成对应的class数据
  • 连接:a验证 b:准备 c:解析
  • 初始化:给类的静态变量赋予初始值

只有在真正使用对应的类时,才会触发初始化(如果类时启动类即main函数所有的类,直接进行new操作 访问静态属性,访问静态方法,用反射访问类,初始化一个类的子类)

/**
 * 饿汉模式
 */
public class HungrySingleTon {

    public static HungrySingleTon hungrySingleTon = new HungrySingleTon();

    private HungrySingleTon(){}

    public static HungrySingleTon getHungrySingleTon(){
        return hungrySingleTon;
    }
}
/**
 * 静态内部类的方式
 */
class InnerClassSingleTonDemo {

    //jdk类加载器,依赖类的加载机制
    private static class InnerClassSingleTon{
        public static InnerClassSingleTonDemo innerClassSingleTonDemo = new InnerClassSingleTonDemo();

    }
    private InnerClassSingleTonDemo(){}

    public static InnerClassSingleTonDemo getIntence(){
        return InnerClassSingleTon.innerClassSingleTonDemo;
    }
}

思考:

使用流从文件中读取一个对象是否和单例中的是同一个实例;

判断一个对象是否是同同一个,最重要的一点就是是否是同一个类加载器创建而成的

    /**
     *  利用反射获取到实例是否和通过静态 方法获取的实例不是同一个
     */
    public static void main(String[] args) throws Exception {
        Constructor<HungrySingleTon> constructor = HungrySingleTon.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        HungrySingleTon hungrySingleTon = constructor.newInstance();
        HungrySingleTon hungrySingleTon1 = HungrySingleTon.getHungrySingleTon();
		//结果:false
        System.out.println(hungrySingleTon==hungrySingleTon1);

    }

通过流获取一个对象实例是否是同一个?


    public static void main(String[] args) {
        HungrySingleTon instance=HungrySingleTon.getHungrySingleTon();
        //第一步:使用输出流生成一个对象文件
//        try(ObjectOutputStream oos=new ObjectOutputStream( new FileOutputStream( "instance" ) )) {
//            oos.writeObject( instance );
//        }
//		使用生成的文件生成一个对象
        try (ObjectInputStream ois=new ObjectInputStream( new FileInputStream( "instance" ) )) {
            HungrySingleTon innerClassSingleton=(HungrySingleTon) ois.readObject();
            System.out.println( innerClassSingleton == instance );
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

枚举天然支持单例

public class EnumSingletonTest {
    public static void main(String[] args) throws IOException {
        EnumSingleton instance=EnumSingleton.INSTANCE;
        EnumSingleton instance1=EnumSingleton.INSTANCE;
        System.out.println(instance==instance1);
        //生成一个对象文件
        try(ObjectOutputStream oos=new ObjectOutputStream( new FileOutputStream( "EnumSingleton" ) )) {
            oos.writeObject( instance );
        }
        //使用枚举的文件反序列化为一个对象
        try (ObjectInputStream ois=new ObjectInputStream( new FileInputStream( "EnumSingleton" ) )){
            EnumSingleton object=((EnumSingleton) ois.readObject());
            System.out.println(object==instance);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
//枚举类
enum EnumSingleton{
    INSTANCE;
    public void print(){
        System.out.println(hashCode());
    }

}

你可能感兴趣的:(积累)