设计模式系列-----------单例模式

来源:互联网 发布:红警3起义时刻知乎 编辑:程序博客网 时间:2024/05/21 07:49

http://cmsblogs.com/?cat=15


单例模式:确保一个类只有一个实例,并提供一个全局访问点。

什么情况下需要单例模式?

      一些类提供公共功能供别人调用,本身不会处理业务逻辑
      类会被许多类和线程调用
单例模式的一些注意点:
     单例的生存期超长,会导致内存的持续占用。
     单例在多线程环境需要小心的处理线程互斥,进行资源保护。
     单例在类的继承树中不利于使用,会破坏继承体系。
     单例的全局可见性带来的设计破坏。

经典代码示例以及改进:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class Singleton {  
  2.     private static Singleton uniqueInstance ;  
  3.   
  4.     public static Singleton getInstance() {  
  5.         if (uniqueInstance == null){  
  6.             uniqueInstance = new Singleton();  
  7.         }  
  8.         return uniqueInstance;  
  9.     }  
  10.   
  11.     private Singleton() {  
  12.     }  
  13. }  
上面的代码实现了延迟加载(假如一个单例类需要耗费好多资源时候延迟加载就有很大好处)但是这种做法在多线程的时候会出现问题,比如有两个线程同时调用getInstance(),这时会new两个对象。

把getInstance()方法变成同步(synchronized)方法:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class Singleton {  
  2.     private static Singleton uniqueInstance ;  
  3.   
  4.     public static synchronized Singleton getInstance() {  
  5.         if (uniqueInstance == null){  
  6.             uniqueInstance = new Singleton();  
  7.         }  
  8.         return uniqueInstance;  
  9.     }  
  10.   
  11.     private Singleton() {  
  12.     }  
  13. }  
但是同步会降低性能。

综合考虑有以下几种解决方案:

1、如果getInstance()的性能对程序不是很关键,那就不用考虑太多。

2、不用延迟实例化的方法。

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class Singleton {  
  2.     private static Singleton uniqueInstance = new Singleton();//在静态初始化器中创建单例,这段代码保证了线程安全  
  3.   
  4.     public static Singleton getInstance() {  
  5.   
  6.         return uniqueInstance;  
  7.     }  
  8.   
  9.     private Singleton() {  
  10.     }  
  11. }  
3、双重检查加锁,在getInstance()中减少使用同步。
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class Singleton {  
  2.     private volatile static Singleton uniqueInstance ;  
  3.   
  4.     public static Singleton getInstance() {  
  5.         if (uniqueInstance == null){//A  
  6.             synchronized (Singleton.class){  
  7.                 if (uniqueInstance == null){//C  
  8.                     uniqueInstance = new Singleton();//B  
  9.                 }  
  10.             }  
  11.         }  
  12.   
  13.         return uniqueInstance;  
  14.     }  
  15.   
  16.     private Singleton() {  
  17.     }  
  18. }  
为什么需要两次判断为null?
其实这个意义在于防止多个线程同时进入第一个if内,比如说线程A执行到A行,线程B执行到B行,线程B还没有返回。当线程A执行到C行,这时线程B初始化实例完毕,如果没有里面的再一次判断就会生成两个实例!

其他需要注意点事项:

1、单例模式和静态类(把所有的方法和变量都定义成静态的)的区别

2、如果程序中存在多个类加载器,则不同的类加载器有可能加载同一个类,这种情况下就会出现多个单例类实例并存。这种情况下则需要自行指定类加载器,并指定同一个类加载器。
0 0