单例设计模式

java中存在很多通用的设计模式,今天我简单总结一下单例设计模式:

解决问题:解决一个类在内存中只存在一个对象的问题(比如说一个软件中的配置文件)

一、如何保证对象的唯一性:

1、为避免建立过多的该类对象,应首先禁止其他应用程序创建该类对象。

2、为让其他应用程序访问到该对象,在本类中自定义一个对象,为避免直接访问该对象,要对其进行私有化。

3、提供访问方式,便于其他程序对自定义对象的访问,提供的访问方法是公有的。

对象保证是惟一的了,那么该如何具体实现呢?

二、使对象唯一性的步骤:

1、将构造函数私有化

2、在类中创建一个本类对象,并设置为私有的

3、提供一个公有的方法获取该对象,便于使用

三、单例设计模式的具体表现形式

具体代码如下:

1、饿汉式:先初始化对象,类一进内存就加载

[java] view plaincopyprint?

  1. <span style="font-family:Arial;font-size:12px;">//饿汉式  
  2. class Single   
  3. {  
  4.     private Single(){}  
  5.     private static Single s = new Single();  
  6.     public static  Single getSingle()  
  7.     {  
  8.         return s;  
  9.     }  
  10. }  
  11.   
  12. class SingleText  
  13. {  
  14.     public static void main(String [] args)  
  15.     {  
  16.         Single s1 = Single.getSingle();  
  17.         Single s2 = Single.getSingle();  
  18.         if (s1==s2)  
  19.             System.out.println(true);  
  20.         else  
  21.             System.out.println(false);        
  22.     }  
  23. }</span>  

 

2、懒汉式:类进内存,对象还没有存在,只有调用了getSingle方法时,才建立对象

[java] view plaincopyprint?

  1. <span style="font-family:Arial;font-size:12px;">//懒汉式  
  2. class Single   
  3. {  
  4.     private Single(){}  
  5.     private static Single s = null;  
  6.     public static Single getSingle()  
  7.     {  
  8.         if (s==null)   
  9.             s = new Single();  
  10.         return s;  
  11.     }  
  12. }  
  13.   
  14. class SingleText  
  15. {  
  16.     public static void main(String [] args)  
  17.     {  
  18.         Single s1 = Single.getSingle();  
  19.         Single s2 = Single.getSingle();  
  20.         if (s1==s2)  
  21.             System.out.println(true);  
  22.         else  
  23.             System.out.println(false);        
  24.     }  
  25. }</span>  

 

运行的结果是:true;这是因为s1s2引用的是同一个对象,所以符合条件。


但是对于第二种懒汉式的单例设计模式,会出现一些小小的问题,当一个线程调用时,是没什么问题的,如果多个线程调用此种方式,那么就会出现问题。

[java] view plaincopyprint?

  1. <span style="font-family:Arial;font-size:12px;">
  2.  
  3. class Single  
  4. {  
  5.     private static Single s = null;  
  6.     private Single(){}  
  7.     public static Single getInstance()  
  8.     {  
  9.         if (s == null)  
  10.         {  
  11.             synchronized(Single.class)  
  12.             {  
  13.                 if (s == null)  
  14.                     s = new Single();  
  15.             }  
  16.         }  
  17.         return s;  
  18.     }  
  19. }</span>  

 

比如说,当A调用时,当读到if(s1==null) 时,可能就停在这了,然后cpu再调用BB也读到if(s1==null)这停下了,cpu再切换到A,接着创建一个对象,A就执行完了;之后B也向下执行,又创建一个对象;此时,对象就不唯一了,就破坏了对象的唯一性的初衷。那么解决方案是这样的:
这利用了锁的机制。synchronizedjava语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。这涉及到了多线程的问题。在这个例子中,比如说,A调用时,当读到第二个if(s1==null) 时,可能就停在这了,然后cpu再调用BB读到第一个if(s1==null)这停下了,因为加上synchronized后,A进去就相当于将其他的调用锁在外面的语句上了,要先执行完A,那么A执行完后,就已经创建了一个对象;当B再读到第二个if(s1==null)的时候不符合就直接结束了。如果再有其他CD等调用的时候,就直接不符合第一个(s1==null)的条件,所以直接返回s。在这里,我们再来看看关于懒汉式的多线程问题:

上面的懒汉式的写法,是效率比较高的,先看看下面一段代码,比较一下,就会清晰很多:

[java] view plaincopyprint?

  1. <span style="font-family:Arial;font-size:12px;">
  2.  
  3. class Single  
  4. {  
  5.     private static Single s = null;  
  6.     private Single(){}  
  7.     public static synchronized Single getInstance()  
  8.     {  
  9.         if (s == null)  
  10.             s = new Single();  
  11.         return s;  
  12.     }  
  13. }</span>  


在这两种方式中,含有双重判断(称为第一种,无双重判断的为第二种)的效率更高,为什呢?虽然第一种和第二种都要先判断一下,但是对于第一种,第一个线程执行完后,s不为null了,那么后面只需要判断s是否为null即可,而对于第二种,要先判断锁,锁里没有线程,再进入,然后再判断一下s是否为null,这样一来,就要判断两次,所以,效率会更低。所以,对于双重判断,是可以提高效率的。

 

问题是解决了,但是相比之下,还是第一种饿汉式的单例设计模式更好一些,是一种建议使用的方式。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值