前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >初遇单例模式之双重检测

初遇单例模式之双重检测

作者头像
用户2141593
发布2019-02-20 14:59:41
6480
发布2019-02-20 14:59:41
举报
文章被收录于专栏:Java进阶Java进阶

为了让博客看起来不那么深入,我觉得可以让加入一点故事情节~ 锻炼一下以后写不动代码改写小说的能力~

最近准备找工作,这不今天就有家喊我去面试的;我一大早的就赶到了公司;

此处省略1万字跟面试官的客套话,直接进入正题;

面试官:小胡,你知道哪些设计模式阿?

我说:设计模式了解得不多,只知道单例模式跟工厂模式,装饰模式,适配器模式,享元模式,观察者模式;

面试官:哟,知道得还挺多的啊,行,先手写一个单例模式来看看;

自信的我迅速的在纸上写上了代码;还不忘加上注释,以体现出自己的代码规范;

代码语言:javascript
复制
	//饿汉式
public class Singleton01 {
	
	//1.将构造方法私有化;不允许外部直接创建对象;
	private Singleton01(){
	}
	
	//2.利用static关键字创建类的唯一实例;依然用private修饰
	private static Singleton01 singleton = new  Singleton01();
	
	//3.对外公开提供一个获取实例的方法,使用 public static修饰
	public static Singleton01 getInstance(){
			return singleton;
	}
	
}

面试官一看,心想还行,不是个浑水摸鱼的,那试探一下,说:那你再写一个懒汉式给我看看;

我:心想这还不简单,饿汉懒汉不都是两个痴汉么?我又迅速的写完了懒汉式;

代码语言:javascript
复制
	//懒汉式
public class Singleton02 {

	//1.将构造方法私有化,还是不允许外部直接用new的方式产生对象
	private Singleton02(){
		
	}
	
	//2.还是使用static关键字,不过这次只是声明一个类的唯一实例而已,我们不急着创建对象~
	private static Singleton02 singleton02;
	
	//3.对外公开提供一个获取实例的方法,使用 public static修饰
	public static Singleton02 getInstance(){
		if(singleton02==null){
			singleton02 = new Singleton02();
		}
		return singleton02;
	}
}

面试官:还不错,代码也挺规范的;

我:此时还挺陶醉的,心想面试也太容易了吧。哈哈~

还没容我乐够三秒,面试官又发话了;

面试官:你看看你写的饿汉式的单例模式,能说说这段代码在什么情况下会出现bug么?

我:还沉醉其中的我,突然慌了...  面试前背的单例模式都是网上找的模板阿,怎么会有bug呢? 我去,我哪知道有什么bug啊。。。 该死的百度,太不靠谱了,此时的我,也没太多的心情去黑百度了;

只能硬着头皮看着自己写的代码,首先私有化构造方法,不让外部直接调用这肯定是没错的;

第二步,使用static关键字保证Singleton02对象在 Singleton02这个类被加载一次已确保会是单例;

第三步,对外提供能够获取实例的方法,先判断Singleton02这个对象存不存在,不存在就创建Singleton02对象,存在就不创建,提升程序运行速度,这也没问题啊,返回值,修饰符都没问题,问题在哪呢? 作为菜鸟的我此时已瑟瑟发抖; 心想面试官不是诈我的吧。

我说:面试官,你好,我检查了一下,貌似没有问题;

面试官:我想,这大概就是你们初级程序员不够稳的地方吧。你仔细看看你懒汉式的第三步的判断,在多线程的情况下;会发生意外!

说个最简单的例子,如果把singleton02比作是一个妹子。你这段代码定的规矩是:如果该妹子为单身,你只要买套房子( new Singleton02() ),然后把这套房子写上妹子的名字,这个妹子就是你女朋友了; 但是,现实情况远远没有你想的那么简单! 你想要这个妹子,别人也想要这个妹子呢!

你看到这个妹子是单身,于是你就去买了一套房子,正准备开开心心的在房产证写上妹子的名字,期待佳人的时候,突然发现妹子已经名花有主了,什么情况?A同学在你看到妹子是单身的时候,他也想追妹子,他跟你一起去小区看的房子,一起付的款,但是A比你先去找房地产公司,先你一步在房产证上写了妹子的名字,妹子是A的了,当然你还是可以写妹子的名字,这样妹子就有两套房子了,但是你女朋友就跟别人跑了。。

此刻的我,恍然大悟,单例模式的初衷是  保证在整个应用程序中某个实例对象有且只会有一个。写饿汉式的时候面试官没有找我的茬是因为第二步对象的创建加了static关键字,在类加载的时候就已经是   加载且只加载一次 ; 所以不会出现线程安全的问题,而懒汉式,第二步只是声明了一个对象而已,并没有创建,创建对象的时候又没有加锁进行同步,也就意味着所有线程只要通过了 if 的那个判断就会去创建对象,如果A线程进入了 if  的判断, 只要new Singleton02()对象没有跟 singleton02 发生引用(看理解为 句柄 或 “指针”关系),那么 singleton02 就还是为null,  此时如果又有B线程进来了,他也会 去new Singleton02()然后赋值给singleton02,此时,就算A线程先进来,女朋友也没了,谁让B线程动作更快呢!

此时的我后悔不已,这么简单的问题怎么就没看出来呢......

面试官看我似乎是因为紧张了没看出来这个问题,于是问我:现在既然你知道会出现线程安全的问题,那么改怎么解决呢?

筐瓢的我,此时已经不能失误了,仔细回忆起脑袋里关系线程安全的知识,加锁,对加锁可以保证线程安全,怎么加?加在哪儿?

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年06月01日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档