2.设计模式--创建者模式--单例设计模式

发布于:2024-07-18 ⋅ 阅读:(140) ⋅ 点赞:(0)

2.设计模式–创建者模式–单例设计模式

一个程序整个运行过程中,该实例的对象只被创建一次。

2.1单例设计模式的分类:

饿汉式:类加载时创建单例类的对象
懒汉式:类加载时不创建单例类的对象,第一次访问时创建单例类的对象。

2.2单例设计模式

2.2.1饿汉式(静态变量)

/**
 * 饿汉式:静态变量创建类的对象
 */
public class Singleton {

    //构造方法私有
    private Singleton(){}

    //静态变量创建类的对象
    private static Singleton instance = new Singleton();

    //对外提供静态方法
    public static Singleton getInstance(){
        return instance;
    }
}

如果对象不创建会导致内存浪费。

2.2.2 饿汉式(静态代码块)

/**
 * 饿汉:静态代码块
 */
public class Singleton2 {

    //构造方法私有
    private Singleton2(){}

    private static Singleton2 instance;
    //静态代码块
    static{
        instance = new Singleton2();
    }

    //对外提供静态对象获取该对象
    public static Singleton2 getInstance(){
        return instance;
    }
}

如果对象不创建会导致内存浪费。

2.2.3 懒汉式(方式一)

/**
 * 懒汉式
 */
public class Singleton3 {

    /**
     * 构造方法私有
     */
    private Singleton3(){};

    //在成员位置创建该类的对象
    private static Singleton3 instance;

    /**
     * 静态获取方法
      * @return
     */
    public static Singleton3 getInstance(){
       if(instance==null){
           instance = new Singleton3();
       }
        return instance;
    }
}

多线程环境,会出现线程安全问题。

2.2.4 懒汉式(方法上synchronized锁)

public class Singleton4 {

    //私有构造方法
    private Singleton4(){};

    //在成员位置创建该类的对象
    private static Singleton4 instance;

    /**
     * 提供静态方法获取变量
     */
    public synchronized static Singleton4 getinstance(){
      if(instance==null){
          instance = new Singleton4();
      }
        return instance;
    }
}

在初始化instance的时候才会出现线程安全问题,一旦初始化完成就不存在了。

2.2.4 懒汉式(双重检查锁)

public class Singleton5 {

    private Singleton5(){};

    private static Singleton5 instance;

    public static Singleton5 getInstance(){
       if(instance==null){
           //第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实例
           synchronized (Singleton5.class){
               //抢到锁之后再次判断是否为null
               if(instance==null){
                   instance = new Singleton5();
               }
           }
       }
        return null;
    }
}

在多线程的情况下,可能会出现空指针问题,出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作

2.2.5懒汉式(volatile关键字)

public class Singleton6 {

    private Singleton6(){};
    //volatile参数存在,不会指令重排序
    private static volatile Singleton6 instance;

    public static Singleton6 getInstance(){
        if(instance==null){
            //第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实例
            synchronized (Singleton6.class){
                //抢到锁之后再次判断是否为null
                if(instance==null){
                    instance = new Singleton6();
                }
            }
        }
        return null;
    }
}

2.2.6懒汉式(静态内部类方式)

public class Singleton7 {

    //私有方法构造
    private Singleton7(){};

    private static class singletonHolder{
        private static final Singleton7 INSTANCE = new Singleton7();
    }

    public static Singleton7 getInstance(){
        return singletonHolder.INSTANCE;
    }
}

静态属性由于被 static修饰,保证只被实例化一次,并且严格保证实例化顺序

3.1破坏单例模式

1.序列化和反序列化

public class SingletonDemo {

    public static void main(String[] args) throws Exception {
        //往文件中写对象
        writeObject2File();
        //从文件中读取对象
        Singleton s1 = readObjectFromFile();
        Singleton s2 = readObjectFromFile();

        //判断两个反序列化后的对象是否是同一个对象
        System.out.println(s1 == s2);
    }

    private static Singleton readObjectFromFile() throws Exception {
        //创建对象输入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\a.txt"));
        //第一个读取Singleton对象
        Singleton instance = (Singleton) ois.readObject();

        return instance;
    }

    public static void writeObject2File() throws Exception {
        //获取Singleton类的对象
        Singleton instance = Singleton.getInstance();
        //创建对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\a.txt"));
        //将instance对象写出到文件中
        oos.writeObject(instance);
    }
}

2.反射

public class Test {
    public static void main(String[] args) throws Exception {
        //获取Singleton类的字节码对象
        Class clazz = Singleton.class;
        //获取Singleton类的私有无参构造方法对象
        Constructor constructor = clazz.getDeclaredConstructor();
        //取消访问检查
        constructor.setAccessible(true);

        //创建Singleton类的对象s1
        Singleton s1 = (Singleton) constructor.newInstance();
        //创建Singleton类的对象s2
        Singleton s2 = (Singleton) constructor.newInstance();

        //判断通过反射创建的两个Singleton对象是否是同一个对象
        System.out.println(s1 == s2);
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到