设计模式概述,单例模式

概述

OOP七大原则
  • 开闭原则: 对拓展开放,对修改关闭
  • 里氏替换原则: 继承必须保证超类所拥有的性质在子类中仍然成立
  • 依赖倒置原则: 要面向接口编程,不要面向现实
  • 单一职责原则: 控制类的粒度大小,将对象解耦,提高内聚
  • 接口隔离原则: 要用各个类建立他们需要的专用接口
  • 迪米特法则: 只与直接朋友交谈,不与“陌生人”通信
  • 合成复用原则: 尽量先使用组合或者内聚等关联关系来实现,其次才考虑使用继承来实现
分类

创建型:单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式

结构型:适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式

行为型:其他

单例模式

场景: 数据库连接池,多线程,Runtime类,Spring中的Bean

饿汉式
/*
 * 饿汉式单例
 * 如果这个实例从未被使用,会造成内存浪费
 * */
public class HungryMan {
    private final static HungryMan hungryMan = new HungryMan();

    private HungryMan() {
        //System.out.println(Thread.currentThread().getName()); 只会执行一次
    }

    public static HungryMan getInstance() {
        return hungryMan;
    }
}

class Test1 {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {
            new Thread(()->{
                HungryMan instance = HungryMan.getInstance();
                //System.out.println(instance);//每个对象都相等
            }).start();
        }
        /*HungryMan instance1 = HungryMan.getInstance();
        HungryMan instance2 = HungryMan.getInstance();
        System.out.println(instance1 == instance2);*/
    }
}
懒汉式

双重检测锁DCL,反射不安全

/*
 * 双重检测锁 懒汉式 DCL
 * */
public class LazyMan {
    private volatile static LazyMan lazyMan;
    private static boolean flag = false;

    //构造方法中也加锁
    private LazyMan() {
        synchronized (LazyMan.class) {
            if (!flag) {
                flag = true;
            } else {
                throw new RuntimeException("不要试图使用反射破坏,异常");
            }
            /*if (lazyMan != null) {
                throw new RuntimeException("不要试图使用反射破坏,异常");
            }*/
        }
        System.out.println(Thread.currentThread().getName());
    }

    public static LazyMan getInstance() {
        if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan();//不是原子操作
                    /*
                     * 1.分配内存空间
                     * 2.执行构造方法,初始化对象
                     * 3.把这个对象指向这个空间
                     * 期待的是123
                     * A线程由于指令重排变成了 132
                     * B线程 进来,发现lazyMan!=null 就直接返回了,就有问题了,此时lazyMan还没有完成构造
                     * 结局:volatile避免指令重排
                     * */
                }
            }
        }
        return lazyMan;
    }
}

class Test2 {
    public static void main(String[] args) throws Exception {
        /*for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                LazyMan instance = LazyMan.getInstance();
                //System.out.println(instance);
            }).start();
        }*/

        //反射破解DCL
        //解决:构造方法中也加锁
       /* LazyMan instance1 = LazyMan.getInstance();
        Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
        constructor.setAccessible(true);
        LazyMan instance2 = constructor.newInstance();
        System.out.println(instance1);
        System.out.println(instance2);//instance1和instance2不是一个对象*/

        //再次破解,只通过反射创建对象,结果又成功了
        //解决:信号灯
        /*Constructor<LazyMan> constructor1 = LazyMan.class.getDeclaredConstructor(null);
        constructor1.setAccessible(true);
        LazyMan instance3 = constructor1.newInstance();
        LazyMan instance4 = constructor1.newInstance();
        System.out.println(instance3);
        System.out.println(instance4);*/

        //再次破击,前提知道了你的信号灯是谁
        Field flag = LazyMan.class.getDeclaredField("flag");
        flag.setAccessible(true);

        Constructor<LazyMan> constructor5 = LazyMan.class.getDeclaredConstructor(null);
        constructor5.setAccessible(true);
        LazyMan instance5 = constructor5.newInstance();
        flag.set(instance5, false);//重新设置信号灯,
        LazyMan instance6 = constructor5.newInstance();
        System.out.println(instance5);
        System.out.println(instance6);
    }
}
posted @   jpy  阅读(4)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示