Singleton-对象创建型模式

单例模式的常见形式如下:  

形式一:

public class Singleton{

private Singleton(){}

        private static Singleton instance = new Singleton{};

public static Singleton getInstance(){

return instance;

}

}

 

这里之所以把构造函数设置成私有的,就是为了防止其它对象私自创建Singleton对象,保证单例的一个策略.

 

形式二:

public class Singleton{

private Singleton(){}

        private static Singleton instance = null;

        public static synchronized  Singleton getInstance(){

if(instance == null){
instance = new Singleton();

return instance;

}

}

 

这个模式个人认为已经是23个经典模式中最为简单,且最被广为人知的几个模式之一了。

但是程序员的世界中,追求极端优化是那些优秀程序员最喜欢干的事,上面的两个代码都是有缺点的:

形式一的缺点是:无论这个模式是不是被使用,都会被创建

形式二的缺点是:所有调用getInstance()的方法都会被进入单线程模式,执行变慢.

 

为了消除这些缺点,有些程序员创建了doubule checked locking idiom,见下:

由于形式二中只有创建的时候是需要单线程的,所以有下面的这个变种,

public class Singleton{

private Singleton(){}

private static Singleton instance =niull;

public static Singleton getInstance(){

if(instance == null){                                          //1
  synchronized(Singleton.class){                 //2

if(instance == null){                          //3

instance == new Singleton();    //4

}

}

}

return instance;

}

}

 

表面看起来这段代码相当的精妙,可是由于jvm的优化,Out-of-order writer引起了一些问题,具体见文章:

dobule checked locking:http://www.ibm.com/developerworks/java/library/j-dcl.html,

这里我只是稍微提点下,因为本人的英文不好,所以看上面文章很吃力,目前也只是半懂,Out-of-order指的是由于有些JVM为了优化性能,在不影响结果的前提下,通常会将代码的执行顺序变动一下,比如创建对象正常的流程应该是:

1.分配内存空间

2.调用构造器

3.将值赋值给instance。

优化后的jvm执行顺序可能会变成

1.分配内存空间

2.将内存空间赋值给instance

3.调用构造器.

 

可能产生的情况如下:

1.线程1进入//1

2.线程1判断instance为null,进入//2的锁

3.线程2进入//1

4.线程2判断instance为null,但是此时锁是在线程1那里,线程2等待

5.线程1进入//3

6.线程1判断instance为null,创建对象,释放锁

7.线程2得到锁,进入到//3

8.由于6中的对象创建只是进行了分配内存空间,将内存空间赋值给instance这两步,所以判断instance非空,返回instance,不过这个instance并不是预期希望获取的值,出错.

 

也有网友对于Out-of-order wirter的问题写了一些解决方案,不过貌似他没看完上面的文章,不过这篇文章的评论是相当的经典,推荐:

对于单例模式的一点想法:http://lucaslee.javaeye.com/blog/211471?page=2#comment

 

private static int hasInitialized=0;  

private static Singleton INSTANCE;  

public static Singleton getInstance(){  

if(hasInitialized==0){  

     synchronized(Singelton.class){  

       //Double checking  

       if(hasInitialized==0){  

         INSTANCE=new Singleton();  

         hasInitialized=1;  

       }  

     }  

   }  

}  

 

文章的主人认为由于hasInitialized这个int类型的操作是原子的,所以这样做就不会出现问题了,如果JVM是按照代码的顺序来执行的,那的确是没有问题了,不过此文的主人没有看完IBM那篇文章下面关于

 

经过广泛讨论,由于jvm的性能优化,在多线程状态下,lazy initial既要高效率又要安全基本不靠谱,最安全的做法还是只有文章的前两种,不过两种性能开销都较大,但是能换来比较安全的执行。 在现实中,一般会使用形式一,第一这些类既然被创建了,基本都会被用到,而且由于只有一个实例,其实从整体而言是大大节省了内存的开销,也变相提升了执行效率。我想目前的单例模式多用于节省内存,配合工厂模式一起使用吧.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值