设计模式之单例设计模式

1.概要

分类优劣
饿汉式线程安全,效率高,不支持懒加载
懒汉式线程安全,效率低,支持懒加载
双重检索式线程安全,效率高,支持懒加载(不建议使用,会出现问题)
静态内部类式线程安全,效率高,支持懒加载
枚举式线程安全,效率高,不支持懒加载,天然防止反射和序列化反序列化

2.代码案例

// 单例模式之饿汉单例
public class Demo1 {
    private static Demo1 instance = new Demo1();//内部封装一个实例,创建类的时候立即生成,这是饿汉式之所以为饿汉式的关键
    private Demo1(){//私有化构造器,使之无法生成实例
    }
    public static Demo1 getInstance(){//使用静态使得在不能创建对象的情况下依旧可以调用方法,从而通过这个入口返回一个实例对象
        return instance;
    }
}
// 单例模式之懒汉单例
public class Demo2 {
    private static Demo2 instance;//没有立即生成实例,这是懒汉式的关键
    private Demo2(){}//私有构造是单例的基础
    public static synchronized Demo2 getInstance(){//因为是同步的原因所以效率低下
        if (null == instance){
            instance = new Demo2();
        }
        return instance;
    }

}
// 单例模式之双重检查锁单例(没懂)不建议使用,会出现问题
public class Demo3 {
    private static Demo3 instance = null;
    private Demo3(){}
    public static Demo3 getInstance(){
        if (null == instance){
            Demo3 demo3;
            synchronized (Demo3.class){
                demo3 = instance;
                if (null == demo3){
                    synchronized (Demo3.class){
                        demo3 = new Demo3();
                    }
                }
            }
           instance = demo3;
        }
        return instance;
    }
}
// 单例模式之静态内部类单例
public class Demo4 {
    private Demo4(){

    }
    private static class Temp{
        private static Demo4 instance = new Demo4();
    }
    public static Demo4 getInstance(){//获取实例的方式不同了
        return Temp.instance;
    }
}
// 单例模式之枚举单例
public enum  Demo5 {
    INSTANCE;
    public void method(){
    }
}
// 多线程状况下测试各模式的效率
public class Client5 {
    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();//开始时间
        int threadNum = 10000;
        final CountDownLatch countDownLatch = new CountDownLatch(threadNum);//用于多线程测试的关键
        for (int i = 0; i < threadNum; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10000; i++) {
                        Demo5.INSTANCE.method();
                    }
                }
            }).start();
            countDownLatch.countDown();
        }
        countDownLatch.await();
        long endTime = System.currentTimeMillis();//结束时间
        System.out.println("耗时:" + (endTime - startTime));
    }
}
// 判断是否是单例
public class Client6 {
    public static void main(String[] args) {
        System.out.println(Demo1.getInstance() == Demo1.getInstance());
        System.out.println(Demo2.getInstance() == Demo2.getInstance());
        System.out.println(Demo3.getInstance() == Demo3.getInstance());
        System.out.println(Demo4.getInstance() == Demo4.getInstance());
        System.out.println(Demo5.INSTANCE == Demo5.INSTANCE);
        
        
    }
}

3.漏洞:反射/序列化反序列化破解单例

反射破解:

      // 反射
       Class<Demo1> clazz = Demo1.class;
       Constructor constructor = clazz.getDeclaredConstructor(null);
       constructor.setAccessible(true);
       Demo1 demo1 = (Demo1) constructor.newInstance();
       System.out.println(demo1==Demo1.getInstance());

反射预防:

// 单例模式之饿汉单例
public class Demo1 {
    private static Demo1 instance = new Demo1();
    private Demo1(){
        // 添加异常处理
        if (null != instance){
           throw new RuntimeException();
        }
    }
    public static Demo1 getInstance(){
        return instance;
    }
}

序列化反序列化破解:

 // 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("Java/src/com/tlx/design/creationalPattern/singletonPattern/text.txt")));
        oos.writeObject(Demo1.getInstance());
        oos.close();

// 反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("Java/src/com/tlx/design/creationalPattern/singletonPattern/text.txt")));
        Demo1 demo11 = (Demo1)ois.readObject();
        System.out.println(demo11==Demo1.getInstance());
        ois.close();
// 目标类必须实现Serializable接口才可以用序列化

防止序列化反序列化破解:

 public Object readResolve() throws ObjectStreamException {
        return instance;
 }
//在目标类中添加如下方法,在序列化时他会检查目标类有没有该方法,如果没有会执行默认的方法

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值