所谓单例模式,就是让一个类在该类的外面只有一个实例
我们知道我们一旦把一个类给声明好了,它有多少个实例,取决于我们new多少次
那什么情况下能让一个类在该类的外面只有一个实例呢?
看下面代码:
class Foo{
private Foo(){}
}
public class Test{
public static void main(String[] args){
}
}
Ok,为了不让它在外面new,干脆把构造器设置为private,保证了不能new多个,但是一个没有也不合适!!
问题又出现了,这样做的结果是“没例模式”!!!
好吧,这样做虽然外面不能new多个,但是在Foo类里面是可以new的
class Foo{
private Foo(){}
public void f1(){
Foo foo1 = new Foo();
Foo foo2 = new Foo();
Foo foo3 = new Foo();
}
}
public class Test{
public static void main(String[] args){
}
}
不能这么去理解,我们所说的单例模式是:不要在Foo类里面new ,而是在Foo类外面只有一个实例!
那肿么办呢?
往下看:
class Foo{
private static Foo instance = new Foo();
private Foo(){}
public static Foo getInstance(){
return instance;
}
}
public class Test{
public static void main(String[] args){
Foo f1 = Foo.getInstance();
Foo f2 = Foo.getInstance();
System.out.println(f1 == f2);
}
}
解释一下吧:
private static Foo instance = new Foo();
现在在main方法里第一次调用了getInstance()方法,这个时候会去加载类
加载类的时候,先走静态块,也就是先执行上面的属性,此时new一个实例,再往下走,经过了构造器,构造器里什么也没执行
最后再执行对外暴露的一个公共方法,返回一个实例
当第二次调用getInstance()方法时,静态块不会再重新加载,保证了只new一次,这次的引用指向的仍是之前的对象
所以最后我们在比较f1 == f2两个的引用地址时,结果是true;
那么我们先把这种称为“饱汉式”,因为它一进来就new了
看下面的懒汉式:
class Foo{
private static Foo instance = null;
private Foo(){}
public static Foo getInstance(){
if(instance == null){
instance = new Foo();
}
return instance;
}
}
public class Test{
public static void main(String[] args){
Foo f1 = Foo.getInstance();
Foo f2 = Foo.getInstance();
System.out.println(f1 == f2);
}
}
分析一下:
我们知道静态属性是隶属于整个类,而不是属于单独的某个实例
当在main方法里第一次调用getInstance()方法时,过程和上面一样,第一次是null,此时创建一个实例,当第二次调用getInstance()方法时,此时的instance已不是null,不会在进if(),保证了只new一次
由于这种方式,在用的时候,才去new,不用的时候,不new,就把它称为“懒汉式”
现在这个程序有点小小的问题,假设这个方法被两个线程调用,当第一个线程顺利通过了if(),正准备new实例时,是有机率被第二个线程所打断的,第二个线程此时new了一个实例,而当此时第一个线程再次努力的抢占cpu成功,它会再从这里继续往下执行,也new一个实例,这个时候,问题就出现了,这就不叫单例了……………
OK,问题暴露出来了,肿么办呢?
现在只能加对象互斥锁了
public static Foo getInstance(){
synchronized(Foo.class){
if(instance == null){
instance = new Foo();
}
}
return instance;
}
当第一次调用getInstance()方法,第一个线程获得了锁,顺利通过if(),此时被第二个线程抢走了cpu,但是第二个线程得不到锁,因为锁在第一个线程手里,所以现在第二个线程只能放弃cpu,让第一个线程顺利往下执行,执行完后,释放cpu,如果另外的线程再拿到锁时,此时instance 已经不是null,就不会再去new了,保证了只new一次,单例模式就OK了
但是它还不够完美,因为每次一个线程过来时候,都要加锁,其实只要第一次加锁就够了,当instance != null,时就没有必要加锁了
所以看下面:
public static Foo getInstance(){
if(instance == null){
synchronized(Foo.class){
if(instance == null){
instance = new Foo();
}
}
}
return instance;
}
好了,这就是双重检测机制,现在看起来有点完美了
如有瑕疵,请多指教…………
<script type="text/javascript">
$(function () {
$('pre.prettyprint code').each(function () {
var lines = $(this).text().split('\n').length;
var $numbering = $('<ul/>').addClass('pre-numbering').hide();
$(this).addClass('has-numbering').parent().append($numbering);
for (i = 1; i <= lines; i++) {
$numbering.append($('<li/>').text(i));
};
$numbering.fadeIn(1700);
});
});
</script>
版权声明:本文为博主原创文章,未经博主允许不得转载。
分享到:
相关推荐
主要介绍了浅谈Spring单例Bean与单例模式的区别,具有一定借鉴价值,需要的朋友可以参考下
单例指的是只能存在一个实例的类(在C#中,更准确的说法是在每个AppDomain之中只能存在一个实例的类,它是软件工程中使用最多的几种模式之一。在第一个使用者创建了这个类的实例之后,其后需要使用这个类的就只能...
单例模式 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 如果我们要让类在一个虚拟机中只能产生一个对象: 将类的...
主要介绍了Python反射 & 单例模式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
主要介绍了Java编程中的单例设计模式,在许多语言的编程过程当中单例模式都被开发者们广泛采用,需要的朋友可以参考下
整理笔记的时候发现以前写的单利设计模式的文章,贴出来给大家分享下!有需要的小伙伴可以来参考下
前言,UML建模技术,深入浅出UML类图,从招式与内功谈起——设计模式概述,面向对象设计原则,工厂三兄弟之简单工厂模式,工厂三兄弟之工厂方法模式,工厂三兄弟之抽象工厂模式,确保对象的唯一性——单例模式,...
工厂三兄弟之抽象工厂模式(二) 工厂三兄弟之抽象工厂模式(三) 工厂三兄弟之抽象工厂模式(四) 工厂三兄弟之抽象工厂模式(五) 单例模式-Singleton Pattern 确保对象的唯一性——单例模式 (一) 确保对象的...
4.7.4 单例模式(Singleton Pattern) 5. 多态(Polymorphism) 5.1 多态的概念 5.2 多态存在的三个必要条件 5.3 TestPolymoph.as —— 多态的应用,体会多态带来的好处 5.4 TestPolymoph 内存分析 5.5 多态的好处 ...
11.单例模式的几种实现方式的及优化? 3 12.作用域的类型有哪些? 5 13.深拷贝和浅拷贝的区别? 5 14.多线程和多进程的区别? 6 15.is是对比地址,==是对比值 6 16. read,readline和readlines 6 17.闭包 6 18.垃圾...
本教程共分为5个部分,第一部分是C语言提高部分,第二部分为C++基础部分,第三部分为C++进阶部分,第四部分为C、C++及数据结构基础部分,第五部分为C_C++与设计模式基础,内容非常详细. 第一部分 C语言提高部分目录...