治疗技术焦虑的方法就是学习!

设计模式-单例模式

设计模式 李新广 1127℃ 0评论

单例模式,说的简单一点,使用了单例模式的类在项目中只会存在一个实例,不管你在哪里引用,用到的都是同一个实例,如果出现了两个一样的实例,就会出现不可预料的错误。
例如在windows中操作系统本地文件时,一次只能一个程序去操作,如果一个程序正在占用文件,你此时去试图操作这个文件,就会告诉你文件正在被占用。显然,系统中操作文件的程序就应该使用单例模式来设计。

下面来看在java中如何获取一个唯一的实例

这里将构造方法设为私有的,防止在其他地方使用new来生成实例。然后提供一个静态方法,在静态方法中判断变量singleton如果为空,就实例化一个,否则就直接返回singleton。
正常情况下这样是没有问题的,但是在并发的情况下就有可能出现被实例化多次的情况。

这里ExecutorService创建了一个线程池,开启了一百个线程去获取Singleton 对象,把获取到的对象转成字符串放在HashSet中,它会自动过滤掉重复的值,然后打印出set中的内容看看。

在一百个线程去访问的情况下,我这边测试出最多的时候生成了三个对象。
原因很简单,如果线程A、线程B同时判断了singleton 是空的,那么就会被singleton 就会被实例化两次。

最直接的解决办法,在getSingleton方法上面加上synchronized,这样保证每次进入方法的只有一个线程。

这样做虽然能保证每次进入方法的只有一个方法,但是这样就会有很多无谓的等待。因为,如果singleton已经被实例化了,后面的线程就只需返回这个实例就行,不必再排队获取这个方法的锁。

所以更好一点的方法是把synchronized加在 if 判断上,如下:

这里对singleton进行了两次是否为空的判断,主要是为了防止下面这种情况发生:线程A判断了singleton为空,然后获取到了线程锁,在他还没有将singleton实例化前,线程B也判断到singleton为空,于是线程B也排队等待获取锁,这时线程A将singleton实例化了,然后它释放了锁,线程B获取执行权力,此时如果不再对singleton进行一次是否为空判断的话,线程B就会再次执行实例化,这样还是被生成了两个对象。

更好的办法:

使用一个内部类,里面包含了一个静态的变量singleton,我们知道使用static修饰的变量在类加载的时候就被初始化,也就被初始化了一次。所以把singleton的实例化交给jvm,很好的保证了singleton是单例。

参考:http://www.cnblogs.com/zuoxiaolong/p/pattern2.html

转载请注明:大道至简 » 设计模式-单例模式

喜欢 (1)or分享 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址