单例模式 Mr

首先我们先看看一个例子,在说什么是单利模式(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 staticvoid main(String[] args) {
Runtime runtime
= Runtime.getRuntime();
runtime.freeMemory();
}
}

上面的例子可以看出在没有使用new,却获得了一个Runtime对象,这是为什么呢?让我们看看java.lang.Runtime.java的源码到底是怎么一回事:

 

publicclass 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:

publicclass Singleton {
privatestatic Singleton instance =null;
private Singleton() {
// ....
}
publicstatic 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)机制:

publicclass Singleton {
privatestatic Singleton instance =null;
private Singleton(){}
synchronizedstaticpublic Singleton getInstance() {
if (instance ==null) {
instance
=new Singleton();
}
return instance;
}
}

 不过这种简单的写法不适合用于像服务器这种服务很多线程的程序上,同步机制会造成相当的效能低落,为了顾及SingletonLazy 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;
}
}

 也就是只有在第一次建立实例时才会进入同步区,之后由于实例已建立,也就不用进入同步区进行锁定。JavaRuntime类别的作法简单的多,它舍弃了Lazy Initialization,如果您要取得单例的机会不是很多,可以用这种方式:

publicclass Singleton {
privatestatic 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
*/
publicclass HungerSingleton {
/**
* 一开始就初始化好了实例
*/
privatestatic HungerSingleton instance =new HungerSingleton();
private HungerSingleton() {
}
publicstatic HungerSingleton getInstance() {
return instance;
}
}


package org.bestupon.dp.singleton;

/**
*
*
@author BestUpon
* @email bestupon@foxmail.com
* @date 2010-6-13上午11:41:22
* @ask 懒汉式单例模式
* @answer
*/
publicclass LazySingleton {
privatestatic LazySingleton instance =null;
private LazySingleton() {
}
publicstatic LazySingleton getInstance() {
if(instance ==null){
instance
=new LazySingleton();
}
return instance;
}
}

4.优点:

在单例模式中,客户调用类的实例时,只能调用一个公共的接口,这就为整个开发团队提供了共享的概念,

5.缺点:

单利模式在实例化后,是不允许类的继承的;在分布式系统中,当系统的单利模式类被复制运行在多个虚拟机下时,在每一个虚拟机下都会创建一个实例对象,此时如果想知道具体哪个虚拟机下运行着单例对象是很困难的,而且单例类是很难实现序列化的。

Mr-sniper
北京市海淀区
邮箱:rafx_z@hotmail.com
原文地址:https://www.cnblogs.com/rafx/p/singleton.html