单利模式的使用

来源:互联网 发布:淘宝店铺手机号 编辑:程序博客网 时间:2024/05/18 10:22

相关的网站:http://wy892648414.blog.163.com/blog/static/2122121352014118104711250/

                 http://blog.csdn.net/sadfishsc/article/details/8007934

单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。在单例模式下,类本身负责保存它的唯一实例,这个类必须保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。单例模式的类中,构造方法(函数/体)被设为private,从而堵死了外部实例化该类的可能。同时,在类中提供一个静态方法负责提供该类的唯一实例,并在实例不存在的情况下试图初始化它。

 

下面的示例展示了单例模式的典型实现:

[java] view plaincopy
  1. public class Singleton {  
  2.     private static Singleton instance;  
  3.      
  4.     private Singleton() {  
  5.          
  6.      
  7.     public static Singleton getInstance(){  
  8.         if (instance == null) {  
  9.             instance = new Singleton();  
  10.         }  
  11.          
  12.         return instance;  
  13.     }  
  14. }  

 

  1.     }  

上述的示例中,单例类中的实例在第一次被引用时才被初始化,这种类型的单例类称为“懒汉式”。单例模式有两种类型,另一种叫“饿汉式”,是指单例类的实例在加载时就被初始化,如下所示:

[java] view plaincopy
  1. public class Singleton {  
  2.     private static Singleton instance = new Singleton();  
  3.      
  4.     private Singleton() {  
  5.          
  6.     }  
  7.      
  8.     public static Singleton getInstance(){  
  9.         return instance;  
  10.     }  
  11. }  

 

单例模式主要用在类需要且仅需要被初始化一次的场合,如UI界面中的工具栏、Android应用中的警告框等等。在单线程程序中,通过上述两种方式生成的单例类就已经可以满足要求了。但是在多线程环境下,情况就麻烦一些:如果多个线程同时实例化某懒汉式的单例类,那么就有可能在单例类内部多次初始化实例,造成单例模式失效。因此,对于多线程程序中的懒汉式单例,还需要对其加锁,确保线程安全。

 

关于Java的同步锁关键字synchronized ,可以参见如下的链接:

http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html

 

简单地说,synchronized 关键字的用法,主要分为两类:

一是方法定义时,加在方法名之前,形如:synchronized   methodName(params){ ... };

二是声明同步块,形如:synchronized(this) { … }。

其作用是给修饰的方法或者代码块加上同步锁。当一个线程执行到这个方法或者代码块的时候,该部分被锁定,之后的其它执行到这些代码的线程被阻塞,直到上一个线程执行完毕,释放同步锁。

 

如下的代码是线程安全的懒汉式单例类的实现:

[java] view plaincopy
  1. public class Singleton {  
  2.     private static Singleton instance;  
  3.     private final static Object syncLock = new Object();  
  4.      
  5.     private Singleton() {  
  6.          
  7.     }  
  8.      
  9.     public static Singleton getInstance(){  
  10.         if (instance == null) {  
  11.             synchronized (syncLock) {  
  12.                 if (instance == null) {  
  13.                     instance = new Singleton();  
  14.                 }  
  15.             }  
  16.         }  
  17.          
  18.         return instance;  
  19.     }  
  20. }  

 

需要注意的是,synchronized同步块处括号中的锁定对象采用的是一个无关的Object类实例。将它作为锁而不是通常synchronized所用的this,其原因是getInstance方法是一个静态方法,在它的内部不能使用未静态的或者未实例化的类对象(避免空指针异常),,除了还方法之外可以使用类名.class的方法来获得该类的字节码对象作为同步锁,就是Singleton.class,该方法比rivate final static Object syncLock = new Object()更好。同时也没有直接使用instance作为锁定的对象,是因为加锁之时,instance可能还没实例化(同样是为了避免空指针异常)。每次进行进入同步代码块之前都要对同步锁进行判断,这样效率大大降低,在同步代码块的外面首先使用 if (instance == null)进行判断,在进入 synchronized (syncLock)进行判断这样可以提高效率,比如第一次线程1创建好了instance对象,当其他线程进入的时候instance已经存在,就不会再执行synchronized (syncLock),不会对同步进行判断,大大提高了效率。下面这种方法,就算创建好了instance对象,但是其他线程每次来都会判断同步锁,降低了效率。

  1. public class Singleton {  
  2.     private static Singleton instance;  
  3.     private final static Object syncLock = new Object();  
  4.      
  5.     private Singleton() {  
  6.          
  7.     }  
  8.      
  9.     public static Singleton getInstance(){  
  10.        
  11.             synchronized (syncLock) {  
  12.                 if (instance == null) {  
  13.                     instance = new Singleton();  
  14.                 }  
  15.             }
  16.       
  17.          
  18.         return instance;  
  19.     }  
  20. }  

此外,单例类中不建议将getInstance方法修饰为synchronized方法,其原因是一旦这样做了,就和上面的情况一样,每次都会判断一次同步锁。

0 0
原创粉丝点击