回归

蓦然回首,那人却在灯火阑珊处

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  4 Posts :: 2 Stories :: 12 Comments :: 0 Trackbacks
      现在大多数Java软件工程师面试都会问到这个问题:什么是单例模式(Singleton),能否写出单例模式的示例代码?单例模式是Gof中23个模式中最简单最容易入门的模式,学习它我们能更理性的感知模式的意义.

     [形成]

      Singleton Pattern 为什么会出现?在我们软件开发和架构中,经常遇到这样的情形:我们需要一个类只能且仅能产生一个实例..比如表示一台计算机的类,表示系统设定的类或者是表示窗口的类,还有为了节约资源,只让产生一个实例..
     
      如何构造这种情形?Singleton模式给我一个方案:


     [代码示例]
      
      程序列表
   

名称

说明

Singleton

只有一个对象实例的类

Main

测试用的类



      [UML图]
   
      

[示例代码和类的诠释]

 1 package singleton;
 2 
 3 public class Singleton {
 4     private static Singleton singleton = new Singleton();
 5 
 6     private Singleton() {
 7         System.out.println("Create instance...");
 8     }
 9 
10     public static Singleton getInstance() {
11         return singleton;
12     }
13 }
14 


          Singleton  Class:
            
            1.该类只能产生一个对象实例

            2.把该类的的singleton属性设定为static再以Singleton;类的对象实例进行初始化,这个初始化的过程仅加载Sington类的时候调用一次.(Line4) 

            3.把Singleton 类的构造函数限定为private,目的是为了防止从非Singleton类(其他类)调用构造函数来产生实例,如果通过new方式来产生Singleton实例,会出现编译错误.这样做是为了保险己见.(Line6) 

            4.要得到Singleton实例的唯一方法就是调用类静态方法getInstance().这个名字可以随便取,只要方便理解就行.(Line 10) 

 1 package singleton;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         System.out.println("Start");
 7         Singleton obj1 = Singleton.getInstance();
 8         Singleton obj2 = Singleton.getInstance();
 9         if(obj1 == obj2){
10             System.out.println("obj1和obj2是同一個對象實例");
11         }else{
12             System.out.println("obj1和obj2不是同一個對象實例");
13         }
14         System.out.println("End");
15     }
16 }
17 


       Main Class
        1.该类是测试程序.
        2.程序通过getInstance()方式产生两个obj1和obj2实例.(Line 7,Line 8)
        3.通过ojb1= =ojb2表达式来确定两个对象是否相同,判定是否产生了Singleton的第二个示例.(Line9-12)
 

示例程序的执行结果
Start
Create instance...
obj1和obj2是同一個對象實例
End

         执行结果含义:
                1. 的确如此,obj1和obj2是Singleton类的同一个且唯一的对象实例. 
                2.当程序执行后,第一次调用getInstance的时候会初始化Singleton类,同时也会初始化static字段,也同时产生产生了一个唯一对象实例.




      [拓展思考]
   
如下的另一一个单例模式的程序有什么隐患?

 1 package singleton;
 2 
 3 public class Singleton2 {
 4     
 5     private static Singleton2 singleton = null;
 6     
 7     private Singleton2(){
 8         System.out.println("已產生對象實例");
 9     }
10     public static Singleton2 getInstance(){
11         if(singleton == null){
12             singleton = new Singleton2();
13         }
14         return singleton;
15     }
16 
17 }
18 

    [解答]
当多线程同时调用Singleton2.getInstance()方法时,可能会产生多个对象实例,例如
public class Main extends Thread{

    
public static void main(String[] args) {
        System.out.println(
"Starts.");
        
new Main("A").start();
        
new Main("B").start();
        
new Main("C").start();
        System.out.println(
"End.");
    }

   
    
public void run(){
        Singleton2 obj 
= Singleton2.getInstance();
        System.out.println(getName()
+": obj ="+obj);
    }

    
    
public Main(String name){
        
super(name);
    }

}




public class Singleton2 {
    
private static Singleton2 singleton2 = null;
    
private Singleton2(){
        System.out.println(
"已产生对象实例");
        solwDown();
    }


    
public static Singleton2 getInstance(){
        
if(singleton2 == null){
            singleton2 
= new Singleton2();
        }

        
return singleton2;
    }

    
     
private  void solwDown(){
         
try{
             Thread.sleep(
1000);
         }
catch(InterruptedException e){
             e.printStackTrace();
         }

     }

}


执行结果:

Start.
End.
已产生对象实例.
已产生对象实例.
已产生对象实例.
B: obj = Singleton2#2a9348
C: obj = Singleton2#b91134
A: obj = Singleton2#e343l12

(#替换为@)

之所以会知道这种情况是因为if(singleton = = null){ singleton = new Singleton2(); }判断不够严谨的导致。
利用: singleton == null 判断为空后去执行new Singleton2()之前,可能会有其他线程来抢先判断表达式singleton == null,从而又执行一遍创建实例的操作。

解决办法:
给getInstance()方法添加Synchronized修饰符,即可修改成线程安全严谨的单例模式。

public class Singleton2 {
    
private static Singleton2 singleton = null;

    
private Singleton2() {
        System.out.println(
"已产生对象实例");
        solwDown();
    }

    
public static synchronized Singleton2 getInstance() {
        
if (singleton == null) {
            singleton 
= new Singleton2();
        }
        
return singleton;
    }

    
private void solwDown() {
        
try {
            Thread.sleep(
1000);
        } 
catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

posted on 2007-06-08 11:36 回归 阅读(1188) 评论(7)  编辑  收藏 所属分类: 個人原創

Feedback

# re: 亲密接触设计模式(二)-------Singleton(单例) 2007-06-08 12:57 dennis
第一个示例少了static
public static Singleton getInstance() {
return singleton;
}
也没有考虑多线程情况下的单例模式  回复  更多评论
  

# re: 亲密接触设计模式(二)-------Singleton(单例) 2007-06-08 16:50 sitinspring
多线程情况下的单例模式:

1 public class Singleton{
2 private static Singleton instance=null;
3
4 public static synchronized Singleton getInstance(){
5 // 要用的时候再把Singleton建立起来
6 if(instance==null){
7 instance=new Singleton();
8 }
9
10 return instance;
11 }
12 }


  回复  更多评论
  

# re: 亲密接触设计模式(二)-------Singleton(单例) 2007-06-11 09:17 一点思想
第一種實行的Singleton不存在多線程隱患,累以第一次加載時候就產生實例.你認為呢?  回复  更多评论
  

# re: 亲密接触设计模式(二)-------Singleton(单例) 2007-06-11 09:22 一点思想
嗯,static寫掉了,這是一個靜態方法,直接通過類名調用  回复  更多评论
  

# re: 亲密接触设计模式(二)-------Singleton(单例) 2007-06-12 15:07 hardson
synchronized 是多余的  回复  更多评论
  

# re: 亲密接触设计模式(二)-------Singleton(单例) 2007-06-18 14:16 想飞就飞
第二种方式需要synchronized 的吧  回复  更多评论
  

# re: 亲密接触设计模式(二)-------Singleton(单例) 2011-03-09 21:03 回归
恩,写掉了,以后注意@一点思想
  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: