BestUpon 写道
首先我们先看看一个例子,在说什么是单利模式(Singleton):
package org.bestupon.dp.singleton;
/**
*
* @author BestUpon
* @email bestupon@foxmail.com
* @date 2010-6-13上午11:08:28
* @ask jdk中Runtime这个类似就是一个单例模式的应用:
*
* @answer
*/
public class Test4RunTime {
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
runtime.freeMemory();
}
}
上面的例子可以看出在没有使用new,却获得了一个Runtime对象,这是为什么呢?让我们看看java.lang.Runtime.java的源码到底是怎么一回事:
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
// 以下略
}
以上是Runtime.java开头部分的代码,我们可以很清楚的看见,一开头就直接 new Runtime(), 一个对象,并且是静态的。在getRuntime()的时候,
直接将其返回给请求的客户端。 上面结构即采用Singleton模式设计,其结构使用 UML 描述如下所示:
Singleton的英文意义是独身,也就是只有一个人,应用在面向对象语言上,通常翻译作单例:单一个实例(Instance)。Singleton模式可以保证一个类别 只有一个实例,并只提供一个访问(visit)这个实例的方法。
1.定义:单例模式就是确保一个类中只有一个实例,并且该实例必须自动创建,并向整个系统提供该实例。
2.使用时机:当系统要求一个类只有一个实例时,就需要使用用单例模式。
有几个实例上面结构的方法,可以在第一次需要实例时再建立对象,也就是采用所谓的Lazy Initialization:
public class Singleton {
private static Singleton instance = null;
private Singleton() {
// ....
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
// .. 其它实例
}
上面的实例适用于单线程的程序,在多线程的程序下,以下的写法在多个线程的竞争资源下,将仍有可能产生两个以上的实例,例如下面的情况:
Thread1: if(instance == null) // true
Thread2: if(instance == null) // true
Thread1: instance = new Singleton(); // 产生一个实例
Thread2: instance = new Singleton(); // 又产生一个实例
Thread1: return instance; // 回传一个实例
Thread2: return instance; // 又回传一个实例
在多线程的环境下,为了避免资源同时竞争而导致如上产生多个实例的情况,加上同步(synchronized)机制:
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
synchronized static public Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
不过这种简单的写法不适合用于像服务器这种服务很多线程的程序上,同步机制会造成相当的效能低落,为了顾及Singleton、Lazy Initialization与效能问题,因而有了Double-check Locking的模式:
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if (instance == null){
synchronized(Singleton.class){
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
也就是只有在第一次建立实例时才会进入同步区,之后由于实例已建立,也就不用进入同步区进行锁定。Java中Runtime类别的作法简单的多, 它舍弃了Lazy Initialization,如果您要取得单例的机会不是很多,可以用这种方式:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
// ....
}
public static Singleton getInstance() {
return instance;
}
// 其它实例
}
Singleton本身的观念简单但应用 很广,因而很多时候必须对实际环境作一些考虑与调整。
3.总结:
单例模式可以分为两种:饿汉式和懒汉式两种,饿汉是在系统启动的一开始就初始化好了实例,而懒汉式是在第一次访问的时候才初始化实例。
package org.bestupon.dp.singleton;
/**
* @author BestUpon
* @email bestupon@foxmail.com
* @date 2010-6-13上午11:34:27
* @ask 饿汉式单利模式
* @answer
*/
public class HungerSingleton {
/**
* 一开始就初始化好了实例
*/
private static HungerSingleton instance = new HungerSingleton();
private HungerSingleton() {
}
public static HungerSingleton getInstance() {
return instance;
}
}
package org.bestupon.dp.singleton;
/**
*
* @author BestUpon
* @email bestupon@foxmail.com
* @date 2010-6-13上午11:41:22
* @ask 懒汉式单例模式
* @answer
*/
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if(instance == null){
instance = new LazySingleton();
}
return instance;
}
}
4.优点:
在单利模式中,客户调用类的实例时,只能调用一个公共的接口,这就为整个开发团队提供了共享的概念,
5.缺点:
单利模式在实例化后,是不允许类的继承的;在分布式系统中,当系统的单利模式类被复制运行在多个虚拟机下时,在每一个虚拟机下都会创建一个实例对象,此时如果想知道具体哪个虚拟机下运行着单例对象是很困难的,而且单例类是很难实现序列化的。
更新(纠正)2010-6-17:
由于端午节放假的缘故,各位同仁在期间提出了很多的问题,也指出了我思维的局限性,没有及时的更新于回复各位好友的,深表遗憾!
针对单例模式的很多用法,前面一直是在所单一线程的问题,本来设计多线程的问题就很少,也对双重锁定这个问题没有深入的五挖掘,导致了犯了今天这样的错误。之后参考了一些资料,针对各位朋友提出的问题与我自身存在的问题,进行改进!参考的文章是:IBMDeveloperWorks(中国)的网站上的文章《双重检查锁定及单例模式》(http://www.ibm.com/developerworks/cn/java/j-dcl.html)。这篇文章真针对各种问题都有分析,包括可见性等问题。得出了一个结论:双重锁定失效的主要原因是:不同JVM之间的无序写入问题,多线程之间的独占、休眠(记忆复苏)所引起的不同不问题。
最终本文提出了一个建议:建议不要使用“双重锁定”!一个解决单例模式的方案:
底线就是:无论以何种形式,都不应使用双重检查锁定,因为您不能保证它在任何 JVM 实现上都能顺利运行。JSR-133 是有关内存模型寻址问题的,尽管如此,新的内存模型也不会支持双重检查锁定。因此,您有两种选择:
接受如清单 2 中所示的 getInstance() 方法的同步。
放弃同步,而使用一个 static 字段。
选择项 2 如清单 10 中所示:
/**
*使用 static 字段的单例实现
**/
class Singleton
{
private Vector v;
private boolean inUse;
private static Singleton instance = new Singleton();
private Singleton()
{
v = new Vector();
inUse = true;
//...
}
public static Singleton getInstance()
{
return instance;
}
}
相关推荐
简单的单例模式举例Singleton 分为恶汉式 懒汉式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个...
单例模式的特点有三: 单例类只能有一个实例。 单例类必须自己创建自己的唯一实例。 单例类必须给所有其他对象提供这一实例。 Singleton模式包含的角色只有一个,就是Singleton。Singleton拥有一个私有构造函数,...
单例模式(Singleton)
该文当中对Java单类模式有非常细致入微的,循序渐进的讲解。
单例模式 Singleton 单例模式线程安全问题和拓展
设计模式C++学习之单例模式(Singleton)
主要介绍了单例模式 Singleton 简单实例设计模式解析的相关资料,需要的朋友可以参考下
java Singleton单例模式 java Singleton单例模式
一个产生随机数的例子,整个应用程序中只需要一个类的实例来产生随机数,客户端程序从类中获取这个实例,调用这个实例的方法nextInt(),公用的方法访问需要进行同步,这是单例模式需要解决的同步问题。
此示例展示了Qml 的单例模式(类似全局对象,只生成一次实例,可全局使用) surfsky.cnblogs.com
单例模式 Singleton Pattern 问题解决: (1)单例模式简介: Singleton模式要求一个类有且仅有一个实例,并且提供了一个全局的访问点。这就提出了一个问题:如何绕过常规的构造器,提供一种机制来保证一个类只有...
Java面向对象(高级)-- 单例(Singleton)设计模式
单例模式(Singleton)的6种实现,单例模式(Singleton)的6种实现
设计模式总结-模板设计模式,单例模式(singleTon)
在Java应用中,单例对象能保证在一个...3、有些像交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了,只有使用单例模式,才能保证核心交易服务器独立控制整个流程。 CSDN代码的详细解释。
4、单例模式(Singleton Pattern) 用意:仅允许生成一个对象时
深入浅出Singleton,详细掌握单例模式
单例设计模式Singleton1