单例模式

强烈推荐的方式:使用枚举:

 

一个错误的单例模式

/*
*   一个有问题的单例模式
* */
public class Single1 {
    private Single1(){}
    private Single1 s = null;

    public Single1 getSingle1(){
        //这样子写有问题
        if (s == null){
            //如果两个程序同时走到这里,就会返回两个实例
            return new Single1();
        }else{
            return s;
        }
    }
}

 

几个普通状态线程安全的单例模式,但是可以被反射破解,也可以被序列化和反序列化破解

/*
*   一个饿汉,安全的单例模式,推荐
* */
public class Single2 implements Serializable {
    private static Single2 s = new Single2();
    private Single2(){}
    public static Single2 getSingle2(){
        return s;
    }
}
package com.zhuopeng.desigh_model.single_model;

import java.io.Serializable;

/*
 *   一个懒汉,双重检查模式,推荐
 *   这个例子,对第一个错误的事例进行了改进。如果不使用双重检查模式,每次调用getInstance()都直接进入同步代码块的话,性能不好
 *   注意:
 *       instance 使用了volatile修饰
 *   原因:代码的重排序,在进行 new Single3()的 时候,需要执行以下的三个步骤
 *   memory=allocate(); //1:分配内存空间
 *   ctorInstance();   //2:初始化对象
 *   singleton=memory; //3:设置singleton指向刚排序的内存空间
 *   如果 2 和 3进行 了重排序, 1-3-2的顺序,如果线程A执行了3,这个时候线程B判断if(instance == null)结果为False,直接返回instance,
 *   就会返回一个没后初始化的instance
 * */
public class Single3 implements Serializable {
    private Single3() {
    }

    private static volatile Single3 instance;

    public static Single3 getInstance() {
        if (instance == null) {
            synchronized (Single3.class) {
                if (instance == null) {
                    instance = new Single3();
                }
            }
        }
        return instance;
    }
}
package com.zhuopeng.desigh_model.single_model;

import java.io.Serializable;

/*
*   懒汉模式,在调用getInstance() 的时候才初始化一个实例,推荐
*   外部的静态变量,静态代码块在加载类的时候就运行了
*   但是内部的静态类,在外部调用的时候才开始执行静态变量,静态代码块
* */
public class Single4 implements Serializable {
    private Single4(){}
    public static Single4 getInstance(){
        return Inner.s;
    }
    private static class Inner{
        private static final Single4 s = new Single4();
    }

}

 

升级过后的单例模式,序列化反序列化之后也只有一个实例,也不可以通过反射破解

package com.zhuopeng.desigh_model.single_model;

import java.io.Serializable;

public class Single6 implements Serializable {
    //设置一个静态的flag,当类加载的时候这个flag就被创建了
    private static boolean flag = false;
    private static Single6 single6 = new Single6();
    private Single6(){
        //当上面那个静态变量new的时候flag就会改变,以后通过反射再次创建的时候,就不能创建了
        if (!flag){
            flag = true;
        }else{
            throw new RuntimeException("单例被破坏");
        }
    }
    public static Single6 getInstance(){
        return single6;
    }
    //用于序列化与反序列化的时候,可能会创建出不同的单例
    private Object readResolve(){
        return single6;
    }

}

一个强烈推荐的:使用枚举的单例模式:

package com.zhuopeng.desigh_model.single_model;


import java.io.Serializable;

public enum  Single5 implements Serializable {
    INSTANCE;
    int id;
    String name;

    public void setId(int id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

 

测试:

package com.zhuopeng.desigh_model.single_model;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/*
*   除了枚举构造的单例模式,其他方法构造的单例模式都可以通过反射来进行破解
*
* */
public class Test1 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //破解使用静态变量构造的单例模式
        Constructor cos = Single2.class.getDeclaredConstructor();
        //取消访问检查功能
        cos.setAccessible(true);
        Single2 s1 = (Single2) cos.newInstance();
        Single2 s2 = (Single2) cos.newInstance();

        //生成了四个实例
        System.out.println(s1);
        System.out.println(s1.getSingle2());
        System.out.println(s2);
        System.out.println(s2.getSingle2());

        //下面是升级版本的,防止破坏的单例模式
        Constructor constructor = Single6.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        //抛出异常,因为Single6的内部静态类已经new出一个实例了
        Single6 s6 = (Single6)constructor.newInstance();
        System.out.println("s6"+ s6);



    }
}
package com.zhuopeng.desigh_model.single_model;

import java.io.*;

/*
*   部分单例模式在序列化和反序列化后会产生多个实例,除非单例类中重写了readResolve() 方法
* */
public class Test2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Single6 single6 = Single6.getInstance();

        FileOutputStream fileOutputStream = new FileOutputStream("o");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(single6);
        objectOutputStream.close();
        fileOutputStream.close();

        FileInputStream fileInputStream = new FileInputStream("o");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Single6 s1 = (Single6)objectInputStream.readObject();
        objectInputStream.close();
        fileInputStream.close();

        //结果显示是一个实例,因为Single6中重写了 readResolve()方法,如果没有重写的话,就是两个不同的实例了
        System.out.println(single6);
        System.out.println(s1);


    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-12-11 19:02  式微胡不归  阅读(173)  评论(0编辑  收藏  举报