java面试常见模式问题---单例模式
短信预约 -IT技能 免费直播动态提醒
1、简介
单例模式使⽤场景:
- 业务系统全局只需要⼀个对象实例,⽐如发号器、 redis 连接对象等。
Spring IOC
容器中的 Bean 默认就是单例。- Spring Boot 中的 Controller、Service、Dao 层中通过
@Autowire
的依赖注⼊对象默认都是单例的。
单例模式分类:
- 懒汉:就是所谓的懒加载,延迟创建对象,需要用的时候再创建对象。
- 饿汉:与懒汉相反,提前创建对象。
- 单例模式实现步骤:
- 私有化构造函数。
- 提供获取单例的方法。
2、单例模式——懒汉式
单例模式——懒汉式有以下⼏种实现⽅式:
public class SingletonLazy {
// 当需要用到该实例的时候再创建实例对象
private static SingletonLazy instance;
private SingletonLazy() {
}
public void process() {
System.out.println("方法实例化成功!");
}
public static SingletonLazy getInstance() {
if (instance == null) {// 实例为null时候才创建
instance = new SingletonLazy();// 当需要的时候再进行实例化对象
}
return instance;
}
public static synchronized SingletonLazy getInstance2() {
if (instance == null) {// 实例为null时候才创建
// 方法上加synchronized锁后可以保证线程安全
instance = new SingletonLazy();// 当需要的时候再进行实例化对象
}
return instance;
}
public static SingletonLazy getInstance3() {
if (instance == null) {// 实例为null时候才创建
// 局部加锁后可以保证线程安全,效率较高
// 缺陷:假设线程A和线程B
synchronized (SingletonLazy.class){
// 当线程A获得锁的执行权的时候B等待 A执行new SingletonLazy();实例化
// 当A线程执行完毕后,B再获得执行权,这时候还是可以实例化该对象
instance = new SingletonLazy();// 当需要的时候再进行实例化对象
}
}
return instance;
}
}
单例模式:懒汉实现 + 双重检查锁定 + 内存模型
对于上面方式三存在的缺陷,我们可以使用双重检查锁定的方式对其进行改进:
public static SingletonLazy getInstance3plus() {
if (instance == null) {// 实例为null时候才创建
// 局部加锁后可以保证线程安全,效率较高
// 假设线程A和线程B
synchronized (SingletonLazy.class){// 第一重检查
// 当线程A获得锁的执行权的时候B等待 A执行new SingletonLazy();实例化
// 当A线程执行完毕后,B再获得执行权,这时候再判断instance == null是否成立
// 如果不成立,B线程无法 实例化SingletonLazy
if (instance == null){// 第二重检查
instance = new SingletonLazy();// 当需要的时候再进行实例化对象
}
}
}
return instance;
}
再次升级方式三,来解决内存模型中的指令重排问题:
// 添加volatile 关键字,禁止实例化对象时,内存模型中出现指令重排现象
private static volatile SingletonLazy instance;
public static SingletonLazy getInstance3plusplus() {
if (instance == null) {// 实例为null时候才创建
// 局部加锁后可以保证线程安全,效率较高
// 假设线程A和线程B
synchronized (SingletonLazy.class){// 第一重检查
// 当线程A获得锁的执行权的时候B等待 A执行new SingletonLazy();实例化
// 当A线程执行完毕后,B再获得执行权,这时候再判断instance == null是否成立
// 如果不成立,B线程无法 实例化SingletonLazy
if (instance == null){// 第二重检查
instance = new SingletonLazy();// 当需要的时候再进行实例化对象
}
}
}
return instance;
}
单例模式——懒汉式调用:
@Test
public void testSingletonLazy(){
SingletonLazy.getInstance().process();
}
3、单例模式——饿汉式
public class SingletonHungry {
// 当类加载的时候就直接实例化对象
private static SingletonHungry instance = new SingletonHungry();
private SingletonHungry(){}
public void process() {
System.out.println("方法实例化成功!");
}
public static SingletonHungry getInstance(){
return instance;// 当类加载的时候就直接实例化对象
}
}
单例模式——饿汉式调用:
@Test
public void testSingletonHungry(){
SingletonHungry.getInstance().process();
}
饿汉式单例模式,当类加载的时候就直接实例化对象,因此不需要考虑线程安全问题。
- 优点:实现简单,不需要考虑线程安全问题。
- 缺点:不管有没有使用该对象实例,instance对象一直占用着这段内存。
懒汉与饿汉式如何选择?
- 如果对象内存占用不大,且创建不复杂,直接使用饿汉的方式即可。
- 其他情况均采用懒汉方式(优选)。
总结
文章会不定时更新,有时候一天多更新几篇,如果帮助您复习巩固了知识点,还请支持一下,后续会亿点点的更新!希望大家多多关注编程网的其他内容!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341