设计系统时,通常希望控制对象的用法,防止用户复制对象或建立新实例。例如,你可以使用它创建一个连接池,每次程序需要往数据库中写入内容时才创建一个新连接的做法并不明智;相反,一个或一组已经在池中的连接就可以使用Singleton模式实例化。
Singleton模式常常和工厂方法模式一同使用,创建一个系统级资源,使用这个资源的代码并不知道它的特殊类型。抽象窗口工具包(AWT)就是组合使用这两个模式的典型例子。在GUI应用程序中,对每个应用程序实例,你一般只需要一个图形元素的实例,如打印(Print)对话框或OK按钮。 3、类图 4、单例模式的运行机制 Singleton是一个无法实例化的对象。这种设计模式暗示,在任何时候,只能由JVM创建一个Singleton(对象)实例。如果实例不存在,你通过创建类的新实例的方法建立一个类来执行这个模式;如果存在类的一个实例,就只会返回那个对象的一个引用。 下面看看单例模式的几种实现方式: 方式1:
方式2:
方式2就是我们说的:滞后初始化(Lazy Initialization)。为什么会有滞后初始化这种实现方式出现呢?我们可用看到在第一种实现方式中无法向单例模式的构造方法传递参数,而使用滞后初始化的方式,我们可用在调用getInstance()方法的时候向方法中传递参数。
凡事有好处必然有坏处,滞后初始化的一个弊病就是在多线程或分布式的环境下有可能出现混乱:
“有时在某些情况下,使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器,跨JVM的。” --摘自www.jdon.com-《GoF 23种设计模式解析》
“在多线程环境下,我们无法保证一个方法能够持续运行到结束,其他线程的方法才开始运行。因而可能存在这样一种情形:两个线程几乎同时尝试初始化单例类。假设第一个方法发现单例为空,而第二个方法在此刻开始运行,它也会发现该单例为空。接下来,这两个方法都将对该单例进行初始化。” --摘自《Java设计模式》 那么在多线程的环境下我们怎么更安全的使用单例模式呢? 方式3: 《Java并发编程》一书建议使用属于当前类的锁进行同步,代码如下:
在第一个线程开始滞后初始化的时候,如果有另一线程也准备开始初始化,这时候,第二个线程将停止执行,等待获取对象classLock的锁。当第二个线程获取这个锁并开始执行初始化的时候,它会发现该单例已不再为空(因为只存在该类的唯有实例,我们可以使用单个静态锁)。 或者:
另一个解决办法是在getInstance()方法声明中添加synchronized关键字:
posted on 2008-05-28 16:57 云淡风清 阅读(733) 评论(0) 编辑 收藏 所属分类: Design Patterns
Powered by: BlogJava Copyright © 云淡风清