设计模式之单例模式

来源:互联网 发布:windows压力测试工具 编辑:程序博客网 时间:2024/06/14 01:54

出处:http://blog.csdn.net/jesson20121020
  

  单例模式也是创建模式中的一种。

单例模式:

  所谓的单例模式,即单一的实例,保证类在内在中只有一个对象。

  举例: windows的打印服务,网络计数器

  应用: 线程池,数据库连接池,Runtime


如何保证类在内存中只有一个对象?

  1. 将构造方法私有化,为了不让外界创建对象

  2.  在类中创建一个对象

  3. 通过一个公共的访问方法给外界提供一个入口。

  

  按照这个步骤,我们可以保证类在内存中只有一个对象,但这里有个问题,就是在第二步“在类中创建对象”时,选择什么时候创建对象,是选择在类加载时创建还是在外界需要时创建呢??这里也就引出了单例模式的两种类型,饿汉式和懒汉式,分别如下:

两种类型的单例模式:

1. 饿汉式

   顾名思义,也就是在类加载时就创建对象,在外界访问时直接通过上述第三步中提供的访问入口访问,而不需再创建。如下例:

Student.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Student {  
  2.     //1. 为了不让外界访问,我们把构造方法私有化  
  3.     private Student(){  
  4.           
  5.     }  
  6.     //2. 创建一个对象  
  7.     //为了满足静态方法访问,这里也必须加一个静态修饰符。  
  8.     //为了不让外界修改s对象,需要在将s私有化,即加私有修饰符private   
  9.     private static Student s = new Student();  
  10.       
  11.     //3. 提供一个公共的访问方法  
  12.     //为了让外界直接访问,我们需要给该方法加一个静态修饰符。  
  13.     public static Student getStudent(){  
  14.         return s;  
  15.     }  
  16.       
  17.     public void show(){  
  18.         System.out.println("我要学好设计模式");  
  19.     }  
  20.       
  21. }  
测试类:

StudentTest.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class StudentTest {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         // TODO Auto-generated method stub  
  8.           
  9.         //下面实质是创建了两个类  
  10.         /*Student s1 = new Student(); 
  11.         Student s2 = new Student(); 
  12.         System.out.println(s1 == s2);*/  
  13.           
  14.         Student s1 = Student.getStudent();  
  15.         Student s2 = Student.getStudent();  
  16.         System.out.println(s1 == s2);  
  17.           
  18.         s1.show();  
  19.         s2.show();  
  20.     }  
  21.   
  22. }  
   这样修改以后,由于将Student类的构造方法私有化了,所以不能直接通过new Student()来创建类了,而是将创建类的工作交给了Student类,为了不让外界对Student类中的创建的Student类直接修改,所以需要将创建的类也私有化,只要给外界提供一个访问对象的方法即可,即上述的getStudent()方法。

  综上所述,饿汉式单例模式是在类加载时就创建对象,即private static Student s = new Student();相应地,在外界需要时创建对象就是懒汉式了,如下。
 

2. 懒汉式

  延迟加载思想:我们什么时候需要,你就什么时候给。(eg. Hibernate)

  也就是说在外界需要的时候创建对象,并且保证类在内存中只有一个,如下例:

Teacher.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:12px;">public class Teacher {  
  2.       
  3.     //为了不让外界创建对象,将构造方法私有  
  4.     public Teacher() {  
  5.         // TODO Auto-generated constructor stub  
  6.     }  
  7.       
  8.     //本类创建一个对象,注意,在这里不能new Teacher(),否则就成饿汉式了  
  9.     //这里加static是为了保证静态方法可以访问  
  10.     //这里加private是为了保证外界不能直接访问  
  11.     private static Teacher t = null;  
  12.       
  13.     //提供公共的访问方法  
  14.     public static Teacher getTeacher(){  
  15.         if(t == null)  
  16.             t = new Teacher();  
  17.         return t;  
  18.     }  
  19.       
  20.     public void show(){  
  21.         System.out.println("我要教好设计模式");  
  22.     }  
  23. }</span>  
测试类

TeacherTest.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:12px;">public class TeacherTest {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         // TODO Auto-generated method stub  
  8.         Teacher t1 = Teacher.getTeacher();  
  9.         Teacher t2 = Teacher.getTeacher();  
  10.         System.out.println(t1 == t2); //true  
  11.           
  12.         t1.show();  
  13.         t2.show();  
  14.     }  
  15.   
  16. }  
  17. </span>  

  可以很容易看出,懒汉式单例模式不仅保证了在内存中只有一个类,而且是在需要的时候创建对象,而不像饿汉式那样,在类加载的时候就创建。

  

  在了解了两种类型的单例模式后,就有一个问题了,在实际的开发和面试中到底选择哪一个呢???

在开发中应该选择哪个单例模式??

  一般我们开发中采用第一种方法,也就是说饿汉式。

  原因: 

    多线程安全问题。饿汉式不存在线程安全问题,而懒汉式存在线程安全问题。

  具体解释:

    在饿汉式的例子中,当有多个线程访问时,比如说有t1和t2同时访问getStudent()时,因为Student 对象是在类一开始加载时就已经创建好的,所以它们不管谁返回都是同一个对象,都是一开始已经创建好的对象,所以不存在线程安全问题。

    在懒汉式的例子中,当有有多个线程访问时,比如有t1和t2同时访问getStudent()时,这个时候,当t1进来后判断这个时候t=null ,所以t1就进去执行if所控制的语句,但是注意了,由于线程的随机性,可能t1刚进去要执行if控制语句,这个时候,被t2抢到了cpu的执行权,这个时候,t2开始执行了,发现,这个时候t还是null,所以t2也进去执行if所控制的语句了,那么将来会有多个对象被创建,因此懒汉式存在线程安全问题。

    因此,在开发中我们一般选择不存在线程安全问题的饿汉式单例模式。 

在面试中一般会选择哪种单例模式??

  在面试中,一般会选择懒汉式单例模式,而且主要是面试以下几个问题:

    A: 延迟加载思想

    B: 线程安全问题

       a: 线程安全问题是怎么产生的??

       b: 线程安全问题是如何解决的??

           ---在存在线程安全问题地方加同步关键字"synchronized"。

              因为被同步的代码,在某一个时刻只能被一个线程访问。

  因此,可以在getTeacher()方法处加入同步关键字"synchronized",以解决懒汉式存在的线程安全问题。


  其实,在JDK中,已经有单例模式的应用了,就是Runtime类,而且是饿汉式单例模式。如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:12px;">public class Runtime {  
  2.     private static Runtime currentRuntime = new Runtime();  
  3.     public static Runtime getRuntime() {  
  4.         return currentRuntime;  
  5.     }  
  6.     private Runtime() {}  
  7. }</span>  
0 0
原创粉丝点击