设计模式的概念与单例模式--带常见面试题

概念

软件设计模式,又称设计模式。是一套被反复使用、多人知晓、代码设计经验的总结。描述了软件设计过程的一些不断重复发生的问题,及该问题的解决方案。是解决特定问题的一系列套路,具有一定普遍性,可以反复使用。

设计模式分类

3类27种---创建型 || 结构性 || 行为型

创建型--单例、原型、工厂方法、抽象工厂、建造者

结构型--代理、适配器、桥接、装饰、外观、享元、组合

行为型--模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器

单例设计模式

单例模式是java最简单的设计模式,这种类型的设计模式属于创建型模式,提供了一种创建对象的最佳方式

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象方式,可以直接访问,不需要实例化该类的对象

单例模式的结构

单例模式主要有单例类和访问类两种角色

单例类只能创建一个实例的类

访问类使用单例类

单例模式的两种实现方式

饿汉式:类加载就会导致该单实例对象被创建

懒汉式:类加载不会导致该实例对象被创建,而是首次使用该对象时才会创建

饿汉式

该方式在成员位置声明Singleton类型的静态变量,并创建Singleton类对象instance。instance对象随着类的加载而创建,如果该对象足够大,而一直不使用就会造成内存浪费

public class Singleton{
    private Singleton(){}	//私有构造方法
    private static Singleton instance = new ehs();	//在成员位置创建该类对象
    public static Singleton getInstance(){	//对外提供静态方法获取对象
        return instance;
    }
}

懒汉式
一、线程不安全

当调用getInstance()方法获取Singleton类对象的时候才创建Singleton类对象,这样就实现了懒加载效果,但是,多线程环境会出现线程安全问题

public class Singleton{
    private Singleton(){}	//私有构造方法
    private static Singleton instance;	//在成员位置创建类对象
    public static Singleton getInstance(){	//对外提供静态方法获取对象
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
二、线程安全

实现懒加载,同时解决线程安全问题,但是在getInstance()方法添加了synchronized关键字,导致该方法执行效果低

public class Singleton{
    private Singleton(){}	//私有构造方法
    private static Singleton instance;	//在成员位置创建该类对象
    public static synchronized Singleton getInstance(){	//对外提供静态方法获取对象
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
三、双重检查锁(常用)

对于getInstance()方法,绝大部分操作都是线程安全的读操作,所以没必要让每个线程必须有锁才能调用方法,需要调整加锁时机。使用volatile关键字解决多线程情况下出现的空指针问题,出现问题的原因是JVM实例化对象的时候进行优化和指令重排序操作,volatile还可以保证可见性和有序性

public class Singleton{
    private Singleton(){}	//私有构造方法
    private static volatile Singleton instance;
    public static Singleton getInstance(){	//对外提供静态方法获取对象
        if(instance == null){	//第一次判断,如果instance不为null,不进入抢锁,直接返回实例
            synchronized(Singleton.class){
                if(instance == null){	//抢到锁再次判断是否为空
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
volatile关键字

第一个作用:防止jvm指令重排

第二个作用:保证变量在多线程运行的可见性

在java内存模型中,volatile关键字作用可以保证可见性或者禁止指令重排。这里是因为singleton = new Singleton(),并非是一个原子操作原子操作,事实上在JVM中上诉语句至少做了三件事:

一、给singleton分配内存空间

二、开始调用Singleton的构造函数初始化singleton

三、将singleton对象指向分配的内存空间(执行完这步singleton就不是null了)

因为存在指令重排序的优化,也就是第2步和3步的顺序是不能保证的,最终执行顺序可能是123或132 如果是132在第三步执行完后singleton就不是null了,可是第二步还没有执行,singleton对象未完成初始化,它的属性值可能不是所预期的值,假设线程2此时进入getInstance方法,由于singleton已经不是null,所以会通过第一重检查并直接返回,但其实这时singleton并没有完成初始化,使用该实例会报错

单例模式优点和缺点

优点:单例类只有一个实例,节省内存资源,对于需要频繁创建销毁的对象,使用单例模式可以提高性能,单例模式可以在系统设置全局访问点,优化和共享数据。

缺点:单例模式一般没有接口,扩展除了修改代码基本上没有途径

懒汉模式和饿汉模式的区别--面试题

懒汉模式优点便是代码中没有使用的情况下,不会加载单例类资源不会造成资源浪费,缺点也明显,加锁同步会带来程序运行效率损失

饿汉模式优缺点恰好与懒汉模式相反,如果明确知道单例对象在程序代码中用的频繁,就可以考虑使用饿汉模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值