设计模式之单例模式

单例:一个类只有一个实例。

实现方式:1.私有化类的对象 2.类的构造函数私有化 3.提供一个公共的方法获取类的对象

demo1:懒汉模式 (实现了lazy 加载 没有加锁 线程不安全)

public class Singleton01 {

    private static Singleton01 instance;

    private Singleton01() {
    }
    public static Singleton01 getInstance() {
        if (instance == null) {
            instance = new Singleton01();
        }
        return instance;
    }

}

demo2:饿汉模式(没有lazy加载 消耗内存)

public class Singleton02 {

    private static Singleton02 instance = new Singleton02();

    private Singleton02() {
    }

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

demo3: 懒汉模式加锁(每次调用执行synchronized 效率低)

public class Singleton03 {
    private static Singleton03 instance;

    private Singleton03() {
    }

    public static synchronized Singleton03 getInstance() {
        if (instance == null) {
            instance = new Singleton03();
        }
        return instance;
    }
}

demo4: 双检锁实现

public class Singleton04 {
    private static Singleton04 instance;

    private Singleton04() {
    }

    private static Singleton04 getInstance() {
        if (instance == null) {
            synchronized (Singleton04.class) {
                if (instance == null) {
                    instance = new Singleton04();
                }
            }
        }
        return instance;
    }
}

demo5:静态内部类实现  静态内部类在调用的时候才初始化,静态属性只初始化一次

public class Singleton05 {

    private static class SingletonHolder {
        private static final Singleton05 INSTANCE = new Singleton05();
    }

    private Singleton05() {
    }

    public static Singleton05 getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

demo6: emun枚举实现

public enum Singleton06 {
    INSTANCE;
}

 

单例模式可以破坏吗? 可以

方式一:通过反射破坏单例类

public class ReflectSingleton {

    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.wl.demo.demos.singleton.Singleton01");
        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton01 s1 = (Singleton01) constructor.newInstance();
        Singleton01 s2 = (Singleton01) constructor.newInstance();

        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(s1.equals(s2));

    }
}

解决办法:构造函数抛出异常:

 private Singleton01() {
        if (instance != null) {
            throw new RuntimeException();
        }
    }

 

方式二:序列化破坏单例

public class BreakSingleton {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Singleton01 s1 = Singleton01.getInstance();
        Singleton01 s2 = Singleton01.getInstance();
        System.out.println(s1 == s2);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\file\\test.txt"));
        oos.writeObject(s1);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\file\\test.txt"));
        Singleton01 s3 = (Singleton01) ois.readObject();
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(s3.hashCode());
        System.out.println(s1 == s3);

    }
}

解决办法:

//反序列化定义该方法,则不需要创建新对象
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }

 

posted @ 2021-12-14 15:55  山阴路的秋天  阅读(29)  评论(0编辑  收藏  举报