- 浏览: 62222 次
- 性别:
- 来自: 苏州
最近访客 更多访客>>
最新评论
-
yuankai:
to seer_lee
final LazySingleto ...
java设计模式全解[1]-单例模式 -
yisonghui:
支持下LZ的无私奉献,对我这种刚入门的人来说还是很通俗易懂的。 ...
java设计模式全解[3]-建造者模式 -
Uranus:
不知道楼主可不可以写一个关于PROTOTYPE模式的文章,我对 ...
java设计模式全解[3]-建造者模式 -
Uranus:
不知道楼主可不可以深入分析下PROTOTYPE模式,我对这个不 ...
java设计模式全解[4]-工厂方法模式 -
zmo_xu:
我的文章是参考某.net大老的设计模式写的 .我在系列文章的第 ...
java设计模式全解[3]-建造者模式
在网上找了很久都没有找到详细分析java 设计模式的 后来在网上找到个.net的 看了后决定 对C#的代码进行java本地化(借用下这个词,不知道把C#变java叫做什么) 不敢独享 拿来与大家分析,当作搬家到javaeye 后zmo_xu给大家的见面礼吧,还请各位高手不要耻笑区区在下(文章有自己的理解也有网上原文,如果你发现zmo_xu个文章里面设计到了你的文章的版权 敬请致电 zmo2xu@gmail.com 我会及时处理),好了言归正传
第1章 单件模式(Single Pattern)
概述
Singleton模式要求一个类有且仅有一个实例,并且提供了一个全局的访问点。这就提出了一个问题:如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?客户程序在调用某一个类时,它是不会考虑这个类是否只能有一个实例等问题的,所以,这应该是类设计者的责任,而不是类使用者的责任。
从另一个角度来说,Singleton模式其实也是一种职责型模式。因为我们创建了一个对象,这个对象扮演了独一无二的角色,在这个单独的对象实例中,它集中了它所属类的所有权力,同时它也肩负了行使这种权力的职责!
意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
生活中的例子
这里这个方法已经线程安全了但是我们知道对一个方法进行线程安全资源消耗是非常大的我们更倾向于对代码的同步 修改后的代码
美国总统的职位是Singleton,美国宪法规定了总统的选举,任期以及继任的顺序。这样,在任何时刻只能由一个现任的总统。无论现任总统的身份为何,其头衔"美利坚合众国总统"是访问这个职位的人的一个全局的访问点。
简单实现:最简单的实现就是在类内声明一个此类的实例并将构造函数私有化(为什么要用private而不用protected来保持可扩展性是因为 当类被继承后影响单例模式) 并向外公开一个getInstance()方法来获取这个实例集体实现 集体实现
java 代码
- package unit;
- public class Singletnon
- {
- private static Singletnon instance;
- private Singletnon()
- {
- }
- public static Singletnon getInstance()
- {
- if(instance==null)
- {
- instance=new Singletnon();
- }
- return instance;
- }
- }
大家可以看到这里的构造方法
是私有的,类外是无法访问的,就是说实现了限制实例化,但是一个类如果没有办法实例化那么这个类将什么也作不了 所以在这个类里面就的提供一个方法来实现实例化 也就是这里的getInstance将在类内对自己实例化并将实例传递出去,好了到此我们已经理解单例模式的实现,那么我们就要考虑安全问题 还有我们是不是真的实现了单例,其实这种模式在多线程模式下是不一定能实现单例模式的稍后我会在后面用一个例子来证明他,现在我们来考虑线程安全,你说synchronized ?,非常好 你已经抓住了问题的关键,我们接着往下走,修改后我们的代码变成了这样
- package unit;
- public class Singletnon
- {
- private static Singletnon instance;
- private Singletnon()
- {
- }
- public synchronized static Singletnon getInstance()
- {
- if(instance==null)
- {
- instance=new Singletnon();
- }
- return instance;
- }
- }
- package unit;
- public class Singletnon
- {
- private static Singletnon instance;
- private static final Object key = new Object();
- private Singletnon()
- {
- }
- public static Singletnon getInstance()
- {
- if (instance == null)
- {
- synchronized (key)
- {
- if (instance == null)
- {
- instance = new Singletnon();
- }
- }
- }
- return instance;
- }
- }
可以看到 zmo_xu在这里引入了一个Object 的对象key 为什么要引入一个key呢 用instance作为同步关键字不是更好吗!这个当然不行,因为线程同步锁锁定的是地址引用 如果你锁定的是instance的化 当你new的时候 地址引用就会改变.线程锁失效,额你说什么 不new 行不行..不new 不new.....不牛,我只能说这些想的人太牛了,要知道我们这里要保护的代码就是为了实例化,我们一定要牛(new)的拉!
单例模式就说到这里 下一次我们将介绍抽象工厂!
javastudy给出的代码补充在这里 !基本上思路是一样的 只是代码实现上有点区别
- //饿汉式:
- public class EagerSingleton {
- private EagerSingleton() { }
- public static EagerSingleton getInstance() {
- return m_instance;
- }
- /** @label Creates */
- private static final EagerSingleton m_instance = new EagerSingleton();
- }
- //懒汉式
- public class LazySingleton
- {
- private LazySingleton() { }
- synchronized public static LazySingleton getInstance()
- {
- if (m_instance == null)
- {
- m_instance = new LazySingleton();
- }
- return m_instance;
- }
- }
- //使用到才实例化 不使用不实例化,比如你使用此类的其他静态方法 而饿汉式只要用到就被实例化
- //登记式:
- import java.util.HashMap;
- public class RegSingletonChild extends RegSingleton
- {
- public RegSingletonChild() {}
- static public RegSingletonChild getInstance()
- {
- return (RegSingletonChild) RegSingleton.getInstance( "com.javapatterns.singleton.demos.RegSingletonChild" );
- }
- public String about()
- {
- return "Hello, I am RegSingletonChild.";
- }
- }
- //这个 嘿嘿 不太明白 待会去看看他的父类原代码
这个帖子的代码部分不会再修改了 就此代码部分封帖 ,希望大家 一起继续讨论共同提高
最后附上所有原代码
- Singleton.rar (4.9 KB)
- 描述: 单例模式的测试代码
- 下载次数: 166
评论
final LazySingleton temp = new LazySingleton(); instance = temp;
java语言规范规定:final引用被赋值给另一个引用时必须被完整初始化,即instance = temp肯定会在初始化构造函数结束后发生.
这个好像不对吧?
final FinalTest fin = null;
FinalTest ft = null;
ft = fin;
我这样用也没有报错啊?
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
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肯定会在初始化构造函数结束后发生
<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/>
另外顺便把你的代码引用到我的帖子里面去了
懒汉式,饿汉式,登记式
.......
到底是什么啦,说清楚点,最好像楼主那样把相应的代码贴出来,谢谢!
也欢迎高手,指出其中的不足,大家一起讨论会更好
<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>
相关推荐
java设计模式中的单例模式,而单例模式又分为饿汉模式和懒汉模式
设计模式--单例模式java例子
JAVA-设计模式-创建型模式-单例模式
Java设计模式-单例模式详解
Java-设计模式-单例模式-实现源码(简单实现、双重检查锁、静态内部类、枚举类)
设计模式-单例模式 学习时候联系的代码,可以进行参考
Java面向对象(高级)-- 单例(Singleton)设计模式
常见设计模式-单例模式
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段...
java设计模式-图解-附代码
java设计模式------------------------------------建造者模式
本文档,详细的描述了单例模式,有类图,java代码实例,以及讲解、注意点,通过这份文档可以让你很容易理解单例设计模式。
java设计模式----抽象工厂模式,简单工厂模式代码 代码内部
java设计模式视频教程-代理模式, 深层了解java的设计模式
Java设计模式-图解-附代码,举例子的方式剖析所有设计模式,更容易理解。
java 设计模式 mvc模式 单例模式 代理 工厂 简单工厂
Java设计模式-图解-附代码