新认识的单例模式

对于编程人员来说,单例模式肯定不会陌生,无论你是否用过,至少你知道这是怎么一回事,就是一个类只有唯一的一个实例。对于代码,我们可以轻松加愉快的很快写出。

package com.baidu.test;

public class One {
	private static One one = null;
	
	private One() {}
	
	public static One getInstance() {
		if (null == one) {
			one = new One();
		}
		return one;
	}
}

这种方式去实现单例模式,是我们很容易想到的,一般我们称这种方式“懒汉式”,因为只有需要的时候才创建,比较懒,正如我们大学学习的时候,只有要考试的时候才会去看课本。

还有一种方式,我们称之为“饿汉式”,具体的代码如下:

package com.baidu.test;

public class One {
	private static One one = new One();
	
	private One() {}
	
	public static One getInstance() {
		return one;
	}
}

因为One这个类的实例是一开始就创建了,比较“饥渴”, 所以称之为“饿汉式”。与懒汉式比起来这里的代码更加的简单,也很容易理解。但是有点不太好的就是,如果这个类我们程序之中并没有用到,而且创建很耗费时间和资源,那对我们开发程序是有一定的影响的。

其实,说到这里,对于上面的大家都知道,单例模式是所有设计模式中最简单的模式,如果仅仅说这么多这篇文章是没有必要的,下面进入今天的重点部分。

对我们上面说道的“懒汉式”,如果在多线程中使用的时候,是否会出现点什么问题呢?请看下面的执行片段:

//A线程执行
public static One getInstance() {
</pre><pre name="code" class="cpp">//B线程可开始执行
public static One getInstance() {
</pre><pre name="code" class="cpp"><pre name="code" class="java">//A线程执行
if (null == one) {
</pre><pre name="code" class="cpp">//B线程执行
if (null == one) {

 
//A线程执行
one = new One();
//B线程执行
one = new One();
 就像上面那样交替的执行,这时候我们就会惊奇的发现,产生了2个实例对象。这难道还是我们所要的单例类么?答案是否定的。 

聪明的你,肯定会想到我可以在getInstance() 方法前面加上 同步synchronized ,这样就解决了产生多个实例的问题,OK, 这种方法绝对是没有问题的,但是细心的你马上又会发现,如果这样似乎对我们的性能有些影响,比如多个线程想得到这个实例读取数据的时候,现在只能一个一个的进行了,不过如果你的程序对于这些额外的负担是可以承受的,那就完全可以这么实现,但是,如果考虑到刚刚我们所说的那种情况呢?

这个时候,迫使我们开始思考,怎样既能实现单例又能考虑性能?

它是被设计用来修饰被不同线程访问和修改的变量

百度百科上对 volatile 的解释是上面;(注:此关键字是在1.5版本开出现的,所以,1.5之前的版本并不能使用下面的方法)

 

package com.baidu.test;

public class One {
	private volatile static One one = null;
	
	private One() {}
	
	public static One getInstance() {
		if (one == null) {
			synchronized (One.class) {
				if (one == null) {
					one = new One();
				}
			}
		}
		return one;
	}
}

使用上面的做法可以大大减少getInstance()所耗费的时间。如果你考虑的是性能,这无疑正是你所需。


其实上面的代码就是控制了类实例化的时候加同步,在使用的时候就和我们上面说到的懒汉式一样了,是不是一个很愉快的解决方案?


到这里,今天的主题多线程中的单例就结束了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值