`
zmo_xu
  • 浏览: 63434 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
最近访客 更多访客>>
社区版块
存档分类
最新评论

java设计模式全解[1]-单例模式

阅读更多

在网上找了很久都没有找到详细分析java 设计模式的 后来在网上找到个.net的 看了后决定 对C#的代码进行java本地化(借用下这个词,不知道把C#变java叫做什么) 不敢独享 拿来与大家分析,当作搬家到javaeye 后zmo_xu给大家的见面礼吧,还请各位高手不要耻笑区区在下(文章有自己的理解也有网上原文,如果你发现zmo_xu个文章里面设计到了你的文章的版权 敬请致电 zmo2xu@gmail.com 我会及时处理),好了言归正传

第1章 单件模式(Single Pattern)

概述



    Singleton模式要求一个类有且仅有一个实例,并且提供了一个全局的访问点。这就提出了一个问题:如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?客户程序在调用某一个类时,它是不会考虑这个类是否只能有一个实例等问题的,所以,这应该是类设计者的责任,而不是类使用者的责任。
从另一个角度来说,Singleton模式其实也是一种职责型模式。因为我们创建了一个对象,这个对象扮演了独一无二的角色,在这个单独的对象实例中,它集中了它所属类的所有权力,同时它也肩负了行使这种权力的职责!


意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

生活中的例子


美国总统的职位是Singleton,美国宪法规定了总统的选举,任期以及继任的顺序。这样,在任何时刻只能由一个现任的总统。无论现任总统的身份为何,其头衔"美利坚合众国总统"是访问这个职位的人的一个全局的访问点。

简单实现:最简单的实现就是在类内声明一个此类的实例并将构造函数私有化(为什么要用private而不用protected来保持可扩展性是因为 当类被继承后影响单例模式) 并向外公开一个getInstance()方法来获取这个实例集体实现 集体实现

java 代码
  1. package unit;   
  2.   
  3. public class Singletnon   
  4. {   
  5.  private static  Singletnon instance;   
  6.     
  7.  private Singletnon()   
  8.  {   
  9.      
  10.  }   
  11.  public static Singletnon getInstance()   
  12.  {   
  13.   if(instance==null)   
  14.   {   
  15.    instance=new Singletnon();   
  16.   }   
  17.   return instance;   
  18.  }   
  19. }   


大家可以看到这里的构造方法

 

是私有的,类外是无法访问的,就是说实现了限制实例化,但是一个类如果没有办法实例化那么这个类将什么也作不了 所以在这个类里面就的提供一个方法来实现实例化 也就是这里的getInstance将在类内对自己实例化并将实例传递出去,好了到此我们已经理解单例模式的实现,那么我们就要考虑安全问题 还有我们是不是真的实现了单例,其实这种模式在多线程模式下是不一定能实现单例模式的稍后我会在后面用一个例子来证明他,现在我们来考虑线程安全,你说synchronized ?,非常好 你已经抓住了问题的关键,我们接着往下走,修改后我们的代码变成了这样

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

 

这里这个方法已经线程安全了但是我们知道对一个方法进行线程安全资源消耗是非常大的我们更倾向于对代码的同步 修改后的代码
java 代码
  1. package unit;   
  2.   
  3. public class Singletnon   
  4. {   
  5.     private static Singletnon instance;   
  6.   
  7.     private static final Object key = new Object();   
  8.   
  9.     private Singletnon()   
  10.     {   
  11.   
  12.     }   
  13.   
  14.     public static Singletnon getInstance()   
  15.     {   
  16.         if (instance == null)   
  17.         {   
  18.             synchronized (key)   
  19.             {   
  20.                 if (instance == null)   
  21.                 {   
  22.                     instance = new Singletnon();   
  23.                 }   
  24.             }   
  25.         }   
  26.         return instance;   
  27.     }   
  28. }   

可以看到 zmo_xu在这里引入了一个Object 的对象key 为什么要引入一个key呢 用instance作为同步关键字不是更好吗!这个当然不行,因为线程同步锁锁定的是地址引用 如果你锁定的是instance的化 当你new的时候 地址引用就会改变.线程锁失效,额你说什么 不new 行不行..不new   不new.....不牛,我只能说这些想的人太牛了,要知道我们这里要保护的代码就是为了实例化,我们一定要牛(new)的拉!

单例模式就说到这里 下一次我们将介绍抽象工厂!

javastudy给出的代码补充在这里 !基本上思路是一样的 只是代码实现上有点区别

  1. //饿汉式:    
  2. public class EagerSingleton {    
  3. private EagerSingleton() { }   
  4.   
  5. public static EagerSingleton getInstance() {    
  6. return m_instance;    
  7. }   
  8.   
  9. /** @label Creates */    
  10. private static final EagerSingleton m_instance = new EagerSingleton();    
  11. }    

 

java 代码
    //懒汉式
  1. public class LazySingleton    
  2. {    
  3. private LazySingleton() { }   
  4.   
  5. synchronized public static LazySingleton getInstance()    
  6. {    
  7.    if (m_instance == null)    
  8.    {    
  9.        m_instance = new LazySingleton();    
  10.    }    
  11.    return m_instance;    
  12.   }   
  13. }
  14. //使用到才实例化 不使用不实例化,比如你使用此类的其他静态方法 而饿汉式只要用到就被实例化
java 代码
  1. //登记式:      
  2.      
  3. import java.util.HashMap;       
  4. public class RegSingletonChild extends RegSingleton       
  5. {       
  6. public RegSingletonChild() {}      
  7.      
  8. static public RegSingletonChild getInstance()       
  9. {       
  10. return (RegSingletonChild) RegSingleton.getInstance( "com.javapatterns.singleton.demos.RegSingletonChild" );       
  11. }      
  12.      
  13. public String about()       
  14. {       
  15. return "Hello, I am RegSingletonChild.";       
  16. }      
  17.      
  18. }      
  19. //这个 嘿嘿 不太明白 待会去看看他的父类原代码     

这个帖子的代码部分不会再修改了 就此代码部分封帖 ,希望大家 一起继续讨论共同提高

最后附上所有原代码

  • Singleton.rar (4.9 KB)
  • 描述: 单例模式的测试代码
  • 下载次数: 166
分享到:
评论
17 楼 yuankai 2008-04-23  
to seer_lee
final LazySingleton temp = new LazySingleton(); instance = temp;
java语言规范规定:final引用被赋值给另一个引用时必须被完整初始化,即instance = temp肯定会在初始化构造函数结束后发生.
这个好像不对吧?
final FinalTest fin = null;
FinalTest ft = null;
ft = fin;
我这样用也没有报错啊?
16 楼 seer_lee 2007-08-05  
另见:
http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html?page=4
http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-toolbox.html
http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html?page=1
15 楼 seer_lee 2007-08-05  
double check懒初始化方法最早由Douglas Schmidt(ACE的作者)提出,double check的线程安全性依赖于处理器的内存同步模型和锁同步机制的内在实现。

java中,double check的线程安全性在某些情况下会被破坏。

非线程安全的几种情况:
1.优化编译器重排JVM字节码
此时可能导致instance = new Singletnon()的执行不像字面显示的那样,而是先创建一个对象,然后赋值给instance,最后执行<init>方法(即构造函数),
在这种情况下,一些线程可能看到赋完值的非null引用,而此时对象的构造函数还并没有被调用,即这些线程看到了脏的中间数据。
2.在多处理器共享存储器环境中,内存的更新不可见,
也可能导致一个线程看不到初始化线程的初始化最终结果,
而读取到中间状态的脏数据。

解决方法:
把instance设置为:private static volatile LazySingleton instance;
这样优化编译器就不会再对instance的赋值指令进行重排,
肯定是发生在<init>函数结束时,
在多处理器共享存储器环境下,也可以保证任何线程对instance的内存更新其他线程都可以看见

注意:
JSE5或者更高的版本中的Java Memory Model和Thread specification保证了上述解决方案的可行性,
在低版本中还会存在线程安全被破坏的情况。

详细可见参考资料:
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
文章详细的讲述了Double Checking方法在Java中的表现。

下面是自己给出的另一种基于final关键字的方案,
没经过实践检验,自己只是觉得从逻辑上应该是对的,
请大家指正!
class LazySingleton {
  private static LazySingleton instance;
  private LazySingleton() {
  }
  public LazySingleton getInstance() {
    if (instance == null) {
      synchronized(this) {
if (instance == null) {
          final LazySingleton temp =
                          new  LazySingleton();
  instance = temp;
}
      }
     }
     return instance;
  }

}

final LazySingleton temp = new  LazySingleton(); instance = temp;
java语言规范规定:final引用被赋值给另一个引用时必须被完整初始化,即instance = temp肯定会在初始化构造函数结束后发生
14 楼 xiumu 2007-07-20  
多谢分享!
13 楼 暗之水晶 2007-07-18  
由于JAVA编译器会重排指令的关系,所以DOUBLE CHECK在JAVA中是无效的.
12 楼 zmo_xu 2007-06-13  
不会啊 我的附件里面代码里面有详细的测试的例子 你可以下载了试试 ..是有2个线程可以进去 但是到了 同步那里 因为第一个线程占掉了key对象  所以第二个线程只能等等,等他能访问key是 说明已经实例化好了 那么里面的instance==null必然是false;所以只能获得实例化好了的实例, 不信你可以看我的附件里面的代码
11 楼 zmo_xu 2007-06-12  
<br/>
<strong>javastudy 写道:</strong><br/>
<div class='quote_div'>
<div class='quote_div'>
<p> <span class='keyword'>public</span><span> </span><span class='keyword'>synchronized</span><span> </span><span class='keyword'>static</span><span> Singletnon getInstance()   </span> </p>
<li class='alt'><span>    {   </span> </li>
<li class=''><span>        </span><span class='keyword'>if</span><span> (instance == </span><span class='keyword'>null</span><span>)   </span> </li>
<li class='alt'><span>        {   </span> </li>
<li class=''><span>            </span><span class='keyword'>synchronized</span><span> (key)   </span> </li>
<li class='alt'><span>            {   </span> </li>
<li class=''><span>                </span><span class='keyword'>if</span><span> (instance == </span><span class='keyword'>null</span><span>)   </span> </li>
<li class='alt'><span>                {   </span> </li>
<li class=''><span>                    instance = </span><span class='keyword'>new</span><span> Singletnon();   </span> </li>
<li class='alt'><span>                }   </span> </li>
<li class=''><span>            }   </span> </li>
<li class='alt'><span>        }   </span> </li>
<li class='alt'>方法还是同步的啊 </li>
</div>
</div>
汉死了 好像是我手误 应该是这样
<div class='code_title'>java 代码</div>
<div class='dp-highlighter'>
<div class='bar'/>
<ol class='dp-j'>
    <li class='alt'><span><span class='keyword'>public</span><span> </span><span class='keyword'>static</span><span> Singletnon getInstance()       </span></span></li>
    <li class=''><span>  </span></li>
    <li class='alt'><span>    {       </span></li>
    <li class=''><span>        </span><span class='keyword'>if</span><span> (instance == </span><span class='keyword'>null</span><span>)       </span></li>
    <li class='alt'><span>        {       </span></li>
    <li class=''><span>            </span><span class='keyword'>synchronized</span><span> (key)       </span></li>
    <li class='alt'><span>            {       </span></li>
    <li class=''><span>                </span><span class='keyword'>if</span><span> (instance == </span><span class='keyword'>null</span><span>)       </span></li>
    <li class='alt'><span>                {       </span></li>
    <li class=''><span>                    instance = </span><span class='keyword'>new</span><span> Singletnon();       </span></li>
    <li class='alt'><span>                }       </span></li>
    <li class=''><span>            }      </span></li>
    <li class='alt'><span>        }    </span></li>
    <li class=''><span>     retuen instance;   </span></li>
    <li class='alt'><span>}   </span></li>
</ol>
</div>
<br/>
<br/>
<br/>
<br/>
10 楼 Terry_Y 2007-06-12  
学习了
9 楼 demoon 2007-06-12  
hao dongxi
8 楼 zmo_xu 2007-06-11  
javastudy 你的懒汉式的和我上面的是一样的啊 我的只是里面加入了线程安全在方法的内部  而你是加载在整个方法上
另外顺便把你的代码引用到我的帖子里面去了
7 楼 laiseeme 2007-06-11  
谁给个三种实现方式的链接
6 楼 longrm 2007-06-11  
javastudy 写道
zmo_xu 写道
三种?你是说?能说一下什么意思吗是关系到安全性什么的还是实现上的.我这里并没有说我这里给出了所有的方式,我只是给出了几个经典的常用模式,而且我也还不知道怎么实现延期实例化的实现,望高手赐教


懒汉式,饿汉式,登记式

.......

到底是什么啦,说清楚点,最好像楼主那样把相应的代码贴出来,谢谢!
5 楼 alexander_xu 2007-06-11  
学习中,希望持续进行!并且能给点好的实例
4 楼 zmo_xu 2007-06-10  
三种?你是说?能说一下什么意思吗是关系到安全性什么的还是实现上的.我这里并没有说我这里给出了所有的方式,我只是给出了几个经典的常用模式,而且我也还不知道怎么实现延期实例化的实现,望高手赐教
3 楼 gitahwang 2007-06-10  
不错,学习中,希望楼主继续,能够学到更多的模式,
也欢迎高手,指出其中的不足,大家一起讨论会更好
2 楼 Eastsun 2007-06-10  
<br/>
<div class='quote_div'><font><blockquote dir='ltr' style='margin-right: 0px;'><font><font><font>
<p> </p>
<p><font/></p>
</font></font></font></blockquote></font>这里这个方法已经线程安全了但是我们知道对一个方法进行线程安全资源消耗是非常大的我们更倾向于对代码的同步 修改后的代码
<div class='code_title'>java 代码</div>
<div class='dp-highlighter'>
<div class='bar'/>
<ol class='dp-j'>
    <li class='alt'><span><span class='keyword'>package</span><span> unit;   </span></span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span/><span class='keyword'>public</span><span> </span><span class='keyword'>class</span><span> Singletnon   </span> </li>
    <li class=''><span>{   </span> </li>
    <li class='alt'><span>    </span><span class='keyword'>private</span><span> </span><span class='keyword'>static</span><span> Singletnon instance;   </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>    </span><span class='keyword'>private</span><span> </span><span class='keyword'>static</span><span> </span><span class='keyword'>final</span><span> Object key = </span><span class='keyword'>new</span><span> Object();   </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>    </span><span class='keyword'>private</span><span> Singletnon()   </span> </li>
    <li class=''><span>    {   </span> </li>
    <li class='alt'><span>  </span> </li>
    <li class=''><span>    }   </span> </li>
    <li class='alt'><span>  </span> </li>
    <li class=''><span>    </span><span class='keyword'>public</span><span> </span><span class='keyword'>synchronized</span><span> </span><span class='keyword'>static</span><span> Singletnon getInstance()   </span> </li>
    <li class='alt'><span>    {   </span> </li>
    <li class=''><span>        </span><span class='keyword'>if</span><span> (instance == </span><span class='keyword'>null</span><span>)   </span> </li>
    <li class='alt'><span>        {   </span> </li>
    <li class=''><span>            </span><span class='keyword'>synchronized</span><span> (key)   </span> </li>
    <li class='alt'><span>            {   </span> </li>
    <li class=''><span>                </span><span class='keyword'>if</span><span> (instance == </span><span class='keyword'>null</span><span>)   </span> </li>
    <li class='alt'><span>                {   </span> </li>
    <li class=''><span>                    instance = </span><span class='keyword'>new</span><span> Singletnon();   </span> </li>
    <li class='alt'><span>                }   </span> </li>
    <li class=''><span>            }   </span> </li>
    <li class='alt'><span>        }   </span> </li>
    <li class=''><span>        </span><span class='keyword'>return</span><span> instance;   </span> </li>
    <li class='alt'><span>    }   </span> </li>
    <li class=''><span>}   </span> </li>
</ol>
</div>
</div>
<p><br/>
<br/>
话说用了两个<span class='keyword'>synchronized同步性能就会提高么?</span></p>
<p><span class='keyword'>感觉里面那个<span class='keyword'>synchronized</span><span> (key) 有画蛇添足之嫌.</span></span></p>
<p><span class='keyword'><span/></span></p>
<p><span class='keyword'><span>关于<span> Singleton 的线程安全问题,Effective JAVA里面已经讲的很清楚,可以用initialize-on-demand holder class:</span></span></span></p>
<p><span class='keyword'><span><span/></span></span></p>
<span class='keyword'><span><span><font>
<div class='code_title'>java 代码</div>
<div class='dp-highlighter'>
<div class='bar'/>
<ol class='dp-j'>
    <li class='alt'><span><span class='keyword'>public</span><span> </span><span class='keyword'>class</span><span>  Singleton {   </span></span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>         </span><span class='keyword'>private</span><span> </span><span class='keyword'>static</span><span> </span><span class='keyword'>class</span><span>  SingletonHandler{   </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>                      </span><span class='keyword'>static</span><span> </span><span class='keyword'>final</span><span>  Singleton  singleton =</span><span class='keyword'>new</span><span>  Singleton();    </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>         }   </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>         </span><span class='keyword'>private</span><span>  Singleton (){}   </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>         </span><span class='keyword'>public</span><span> </span><span class='keyword'>static</span><span>  Singleton getInstance(){   </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>                    </span><span class='keyword'>return</span><span> SingletonHandler.singleton;   </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>         }   </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>}   </span> </li>
</ol>
</div>
<p><br/>
</p>
</font></span></span></span>
<p><br/>
<br/>
</p>
1 楼 zmo_xu 2007-06-10  
莫名的提交失败,受不了,我只能修改点提交再修改,有点受不了的说

相关推荐

    设计模式-单例模式

    **设计模式——单例模式** 单例模式是一种广泛应用于软件设计中的创建型设计模式,它的核心思想是确保一个类只有一个实例,并提供一个全局访问点。这样做的好处在于控制共享资源的访问,比如线程安全的数据库连接池...

    常见设计模式-单例模式

    单例模式是设计模式中的一种,其主要目的是确保一个类只有一个实例,并且提供一个全局访问点来获取这个实例。在Java编程中,实现单例模式有多种方式,每种方式都有其优缺点。 1. **饿汉式**: 饿汉式在类加载时即...

    设计模式-单例模式(讲解及其实现代码)

    单例模式是软件设计模式中的一种,它保证一个类只有一个实例,并提供全局访问点。这种模式在许多场景下非常有用,比如控制共享资源、管理系统级别的对象,如数据库连接池或者线程池等。单例模式的核心在于限制类的...

    java-单例模式几种写法

    单例模式是软件设计模式中的一种,用于控制类的实例化过程,确保一个类只有一个实例,并提供全局访问点。在Java中,实现单例模式有多种方法,每种方法都有其特点和适用场景。以下是对这六种常见单例模式实现方式的...

    java设计模式----源代码

    1. **单例模式(Singleton)**:保证一个类只有一个实例,并提供一个全局访问点。在Java中,通常通过私有构造器和静态工厂方法实现。文件`Singleton`可能包含了不同实现单例的示例,如饿汉式、懒汉式和双重检查锁定等...

    Java与模式---闫宏

    3. **设计模式分类**:常见的设计模式分为三大类:创建型模式(如工厂模式、抽象工厂模式、单例模式等)、结构型模式(如适配器模式、桥接模式、装饰器模式等)和行为型模式(如观察者模式、策略模式、命令模式等)...

    JAVA设计模式--程序设计--反射--注解--泛型

    设计模式包括创建型模式(如单例、工厂方法、抽象工厂等)、结构型模式(如适配器、装饰器、代理等)和行为型模式(如策略、观察者、职责链等)。这些模式提供了良好的可复用性和可扩展性,帮助开发者遵循“开闭原则...

    计算机后端-Java-图解java设计模式037 单例模式JK.avi

    计算机后端-Java-图解java设计模式037 单例模式JK.avi

    Java设计模式 pdf 示例代码 刘伟

    这是我见过的最好的设计模式讲解资料。为什么这么说呢?因为它不像其他的书籍那样,只讲解原理,还把每个设计模式的由来动机也讲解得很详细。它的讲解思路为:模式动机-&gt;模式定义-&gt;模式结构-&gt;模式分析(即原理)-&gt;...

    设计模式课程设计---使用5个以上不同的设计模式完成(java)

    在本设计模式课程设计中,我们重点探讨了五个核心的设计模式:原型模式、单例模式、抽象工厂模式、代理模式和建造者模式。这些模式在Java编程中具有广泛的应用,能够帮助开发者创建更加灵活、可扩展和易于维护的代码...

    JAVA设计模式(java设计)

    - 单例模式:确保一个类只有一个实例,并提供全局访问点。 - 工厂模式:提供一个接口来创建相关或依赖对象,而无需指定具体类。 - 抽象工厂模式:为一组相关的对象提供一个统一的接口,使客户类与具体实现解耦。 ...

    Java设计模式之单例模式讲解

    入名所示,该文件为最详细的Java单例模式讲解并附有讲解代码。主要讲了单例模式的几种方法,懒汉模式、饿汉模式、静态内部类模式。着重讲解了懒汉模式下怎么实现线程安全。饿汉模式和静态内部类模式如何设置能够避免...

    计算机后端-Java-图解java设计模式036 单例(.avi

    计算机后端-Java-图解java设计模式036 单例(.avi

    计算机后端-Java-Java核心基础-第15章 面向对象07 14. 设计模式与单例设计模式.avi

    计算机后端-Java-Java核心基础-第15章 面向对象07 14. 设计模式与单例设计模式.avi

    《Java设计模式》刘伟 课后习题及模拟试题答案.rar

    《Java设计模式》是刘伟老师的一本经典教材,它深入浅出地讲解了软件设计中的重要概念——设计模式。设计模式是经验丰富的开发者在解决常见问题时总结出的通用解决方案,是软件开发中的智慧结晶。这本书的课后习题和...

    计算机后端-Java-图解java设计模式029 单例(静态常.avi

    计算机后端-Java-图解java设计模式029 单例(静态常.avi

    三种工厂设计模式和两种单例模式

    在本文中,我们将深入探讨三种工厂设计模式——简单工厂模式、抽象工厂模式和工厂方法模式,以及两种单例模式——饿汉单例模式和懒汉单例模式。这些模式都是面向对象设计中的重要组成部分,对于理解和构建可维护、可...

    JAVA设计模式-chm版

    这类模式关注对象的创建过程,包括单例模式(Singleton)、工厂模式(Factory)、抽象工厂模式(Abstract Factory)、建造者模式(Builder)和原型模式(Prototype)。它们提供了创建对象的不同策略,使代码更加灵活...

    Java设计模式之单例模式的七种写法

    Java设计模式之单例模式的七种写法 单例模式是一种常见的设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机的驱动程序对象常...

Global site tag (gtag.js) - Google Analytics